接着上文写
七. 重写功能
Nginx 服务器利用 ngx_http_rewrite_module 模块解析和处理 rewrite 请求,此功能依靠 PCRE (perl compatible regular expression),因此编译之前要安装PCRE库,rewrite 是 nginx 服务器的重要功能之一,用于实现URL的重写,URL的重写是非常有用的功能,比如它可以在我们改变网站结构之后,不需要客户端修改原来的书签,也无需其他网站修改我们的链接,就可以设置为自动访问,另外还可以在一定程度上提高网站的安全性。
7.1 ngx_http_rewrite_module模块指令
官方文档: Module ngx_http_rewrite_module
7.1.1 if 指令
用于条件匹配判断,并根据条件判断结果选择不同的Nginx配置,可以配置在server或location块中进行配置,Nginx的if语法仅能使用if做单次判断,不支持使用if else或者if elif这样的多重判断,用法如下:
格式:
if (条件匹配) { action
}
使用正则表达式对变量进行匹配,匹配成功时if指令认为条件为true,否则认为false,变量与表达式之间使用以下符号链接:
=
#比较变量和字符串是否相等,相等时if指令认为该条件为true,反之为false
!=
#比较变量和字符串是否不相等,不相等时if指令认为条件为true,反之为false~
#区分大小写字符,可以通过正则表达式匹配,满足匹配条件为真,不满足匹配条件为假
!~
#区分大小写字符,判断是否匹配,不满足匹配条件为真,满足匹配条件为假~*
#不区分大小写字符,可以通过正则表达式匹配,满足匹配条件为真,不满足匹配条件为假
!~*
#不区分大小字符,判断是否匹配,满足匹配条件为假,不满足匹配条件为真-f 和 !-f #判断请求的文件是否存在和是否不存在-d 和 !-d #判断请求的目录是否存在和是否不存在-x 和 !-x #判断文件是否可执行和是否不可执行-e 和 !-e #判断请求的文件或目录是否存在和是否不存在(包括文件,目录,软链接)
location /main {index index.html;default_type text/html;if ( $scheme = http ){echo "if-----> $scheme";}if ( $scheme = https ){echo "if ----> $scheme";}#if (-f $request_filename) {# echo "$request_filename is exist";#}if (!-e $request_filename) {echo "$request_filename is not exist";#return ;}}
案列①
案列②
location /test{if (!-e $request_filename) {echo "$request_filename is not exist";
}
}#如果访问的文件不存在,就打印 xxx文件不存在这句话
案列③
location /test{if (!-e $request_filename) {return 301 http://www.baidu.com;
}
}#访问页面不存在就跳转到百度
7.1.2 return
return 用于完成对请求的处理,并直接向客户端返回响应状态码,比如:可以指定重定向 URL (对于特殊重定向状态码,301/302等) 或者是指定提示文本内容(对于特殊状态码403/500等),处于此指令后的所有配置都将不被执行,return可以在server、if 和 location块进行配置
语法格式:
return code; #返回给客户端指定的HTTP状态码return code [text]; #返回给客户端的状态码及响应报文的实体内容,可以调用变量,其中text如果有空格,需要用单或双引号return code url; #返回给客户端的URL地址
location /main {index index.html;default_type text/html;if ( $scheme = http ){return 666 "if-----> $scheme"; #如果是http的 打印http}if (!-e $request_filename){return 302 /index.html; #如果用户不存在,返回302,直接跳转到主页面}
任意跳转:
location / {root /data;if (!-e $request_filename){return 302 http://www.baidu.com;
}
}
301 和 302区别
301 永久重定向 读取过一次,就会将此条配置缓存在我们的客户端,即使 nginx 服务器宕机,在缓存时间内,还是可以跳转。
302 临时重定向 不会有缓存在客户端,每次跳转需要 nginx 服务器解析,一旦服务器宕机就无法跳转
自定义内容:
只可以文字浏览器访问:
如果想图像化浏览器访问:
加之前
加上之后
7.1.3 set
指定key并给其定义一个变量,变量可以调用Nginx内置变量赋值给key,另外set定义格式为set $key value,value可以是text, variables和两者的组合。
location /main {root /data/nginx/html/pc;index index.html;default_type text/html;set $name kgc;echo $name;set $my_port $server_port(nginx 自带的变量 服务端口 一般80);echo $my_port;
}
7.1.4 break
用于中断当前相同作用域(location)中的其他Nginx配置,与该指令处于同一作用域的Nginx配置中,位于它前面的配置生效,位于后面的 ngx_http_rewrite_module 模块中指令就不再执行,Nginx服务器在根据配置处理请求的过程中遇到该指令的时候,回到上一层作用域继续向下读取配置,该指令可以在server块和locationif块中使用
注意: 如果break指令在location块中后续指令还会继续执行,只是不执行 ngx_http_rewrite_module 模块的指令,其它指令还会执行
location /main {root /data/nginx/html/pc;index index.html;default_type text/html;set $name kgc;echo $name;break; #location块中break后面指令还会执行set $my_port $server_port;echo $my_port;}
注意: 如果break指令在location块中后续指令还会继续执行,只是不执行 ngx_http_rewrite_module 模块的指令,其它指令还会执行。
7.2 rewrite
通过正则表达式的匹配来改变URI,可以同时存在一个或多个指令,按照顺序依次对URI进行匹配,rewrite主要是针对用户请求的URL或者是URI做具体处理.
语法格式:
rewrite可以配置在 server、location、if
语法格式 :
rewrite regex replacement(www.baidu.com) [flag];正则匹配原始访问url 替代你想让客户访问的 标志 ()premanent301 redirect302 break last
rewrite 将用户请求的URI基于regex所描述的模式进行检查,匹配到时将其替换为表达式指定的新的URI
正则表达式格式:
. #匹配除换行符以外的任意字符
\w #匹配字母或数字或下划线或汉字
\s #匹配任意的空白符
\d #匹配数字 [0-9] 。。
\b #匹配单词的开始或结束
^ #匹配字付串的开始
$ #匹配字符串的结束
* #匹配重复零次或更多次
+ #匹配重复一次或更多次
? #匹配重复零次或一次
{n} #匹配重复n次
{n,} #匹配重复n次或更多次
{n,m} #匹配重复n到m次
*? #匹配重复任意次,但尽可能少重复
+? #匹配重复1次或更多次,但尽可能少重复
?? #匹配重复0次或1次,但尽可能少重复
{n,m}? #匹配重复n到m次,但尽可能少重复
{n,}? #匹配重复n次以上,但尽可能少重复
\W #匹配任意不是字母,数字,下划线,汉字的字符
\S #匹配任意不是空白符的字符
\D #匹配任意非数字的字符
\B #匹配不是单词开头或结束的位置
[^x] #匹配除了x以外的任意字符
[^xyl] #匹配除了xyl 这几个字母以外的任意字符
rewrite flag 使用介绍
利用nginx的rewrite的指令,可以实现url的重新跳转,rewrtie有四种不同的flag,分别是 redirect(临时重定向302)、permanent(永久重定向301)、break和last。其中前两种是跳转型的flag,后两种是代理型
-
跳转型指由客户端浏览器重新对新地址进行请求
-
代理型是在WEB服务器内部实现跳转
redirect;302
#临时重定向,重写完成后以临时重定向方式直接返回重写后生成的新URL给客户端,由客户端重新发起请求;使用相对路径,或者http://或https://开头,状态码:302permanent;301
#重写完成后以永久重定向方式直接返回重写后生成的新URL给客户端,由客户端重新发起请求,状态码:301break;
#重写完成后,停止对当前URL在当前location中后续的其它重写操作,而后直接跳转至重写规则配置块之后的其它配置;结束循环,建议在location中使用
#适用于一个URL一次重写
#一次匹配last;
#重写完成后,停止对当前URI在当前location中后续的其它重写操作,而后对新的URL启动新一轮重写检查,不建议在location中使用
#适用于一个URL多次重写,要注意避免出现超过十次以及URL重写后返回错误的给用户301
#多次匹配
操作:
案列① nj 跳转 nanjing
以nj开头的,跳转到nanjing
location /nj{rewrite ^/nj/(.*) /nanjing/$1 permanent;}#访问nj 跳转到nanjing
# $1 后项引用
案列② http 转 https
针对全站跳转
location / { #针对全站跳转if ( $scheme = http ) { #如果不加条件判断,会导致死循环rewrite /(.*) https://$host/$1 permanent;
}
}
非全站跳转,页面跳转
案列③ last 和 break 区别
案例④ 小题目
更换目录访问方式,目录转换为对象存储形式
rewrite ^/(\d+)/(.+)/ /$2?id=$1 last;^以这个文件开头的
\d+ 一个以上数字
.+ 一个以上字符
多目录转换访问方式
7.3 防盗链
防盗链基于客户端携带的 referer 实现,referer 是记录打开一个页面之前记录是从哪个页面跳转过来的标记信息,如果别人只链接了自己网站图片或某个单独的资源,而不是打开了网站的整个页面,这就是盗链,referer 就是之前的那个网站域名,正常的 referer 信息有以下几种:
none: #请求报文首部没有 referer 首部,
比如用户直接在浏览器输入域名访问web网站,就没有referer信息。blocked: #请求报文有 referer 首部,但无有效值,
比如为空。server_names: #referer首部中包含本主机名及即nginx 监听的server_name。arbitrary_string: #自定义指定字符串,但可使用*作通配符。
示例: *.kgc.org www.kgc.*regular expression:#被指定的正则表达式模式匹配到的字符串,要使用~开头
示例: ~.*\.kgc\.com
被盗图使用:
7-2 服务器的图片
7-3
去真机上添加dns解析
C:\Windows\System32\drivers\etc hosts 文件
这张图片在.20上,但被我.30盗用显示,点击量算.30的,消耗的资源还算.20的
做防盗链:
图片访问不到,直接返回403
可以自定义返回的图片:
八.反向代理
正向代理:代理的是客户端去访问服务端
反向代理:代理的是服务端
1. 定义
反向代理:reverse proxy,指的是代理外网用户的请求到内部的指定的服务器,并将数据返回给用户的一种方式,这是用的比较多的一种方式。
Nginx 除了可以在企业提供高性能的web服务之外,另外还可以将 nginx 本身不具备的请求通过某种预定义的协议转发至其它服务器处理,不同的协议就是Nginx服务器与其他服务器进行通信的一种规范,主要在不同的场景使用以下模块实现不同的功能。
2.模块
ngx_http_proxy_module: #将客户端的请求以http协议转发至指定服务器进行处理ngx_http_upstream_module #用于定义为proxy_pass,fastcgi_pass,uwsgi_pass等指令引用的后端服务器分组 负载均衡ngx_stream_proxy_module:#将客户端的请求以tcp协议转发至指定服务器处理 四层代理ngx_http_fastcgi_module:#将客户端对php的请求以fastcgi协议转发至指定服务器助理ngx_http_uwsgi_module: #将客户端对Python的请求以uwsgi协议转发至指定服务器处理
同构协议:代理服务器两边请求一样
异构协议:代理服务器两边请求不一样
主配置里面,PHP语言的程序模板已经写好:
3. 实现 http 反向代理
3.1 反向代理配置参数
proxy_pass;
#用来设置将客户端请求转发给的后端服务器的主机,可以是主机名(将转发至后端服务做为主机头首部)、IP
地址:端口的方式
#也可以代理到预先设置的主机群组,需要模块 ngx_http_upstream_module 支持示例:
10.0.0.8/weblocation /web {index index.html;proxy_pass http://10.0.0.18:8080;
#如果你访问10.0.0.8/web 就相当于访问10.0.0.18:8080
##8080后面无uri,即无 / 符号,需要将location后面url 附加到proxy_pass指定的url后面,此行为类似于root重点:
如果location定义其uri时使用了正则表达式模式(包括~,~*,但不包括^~),则proxy_pass之后必须不能使用uri; 即不能有/ ,用户请求时传递的uri将直接附加至后端服务器之后
server {...server_name HOSTNAME;location ~|~* /uri/ {proxy_pass http://host:port; # proxy_pass 后面的 url 不能加/}...}proxy_hide_header field;
#用于 nginx 作为反向代理的时候,在返回给客户端 http 响应时,隐藏后端服务器相应头部的信息,可以设置
在http,server或location块#示例: 隐藏后端服务器ETag首部字段location /web {index index.html;proxy_pass http://10.0.0.18:8080/; proxy_hide_header ETag;}proxy_pass_header field;
#默认nginx在响应报文中不传递后端服务器的首部字段Date, Server, X-Pad, X-Accel等参数,如果
要传递的话则要使用 proxy_pass_header field 声明将后端服务器返回的值传递给客户端
#field 首部字段大小不敏感#示例:透传后端服务器的 Server 和 Date 首部给客户端,同时不再响应报中显示前端服务器的Server字段
proxy_pass_header Server;
proxy_pass_header Date;proxy_pass_request_body on | off;
#是否向后端服务器发送HTTP实体部分,可以设置在http,server或location块,默认即为开启proxy_pass_request_headers on | off;
#是否将客户端的请求头部转发给后端服务器,可以设置在http,server或location块,默认即为开启
3.2 实战:反向代理单台web服务器
3.2.1 proxy_pass
3.2.2 其他一些操作
① 在真实服务器上,做防火墙规则
iptables -A INPUT -s 192.168.44.20 -j DROP
#拒绝所有来自 192.168.44.20 的请求客户端再次访问 会出现504网关超时(有可能只是处理时间久,服务器不一定挂了),时间较长1分钟,没有定义代理超时时间iptables -A INPUT -s 192.168.91.20 -j REJECT
客户端再次访问 会出现502,一般出现502 代表后端真实服务器挂了
出现504 应排查代理端到真实服务器这一端
出现502 直接拒绝你,代表后端真实服务器挂了
② 504 和 502 区别
502 一般出现502,代表后端真实服务器挂了
504 网关超时 (有可能只是单纯处理时间久,服务器不一定挂了)
③ 加 / 与不加 /
不加 是追加
加 / 是替换
总结:
加 / 是替换 显示 welcome to my world 是将 location 上的url 替换后 proxy 配置里的连接
不加 / 是追加 显示 api 是将 location 上的url 追加在后面
④ 使用 ~ ~*正则搭配 / 报错
如果 location 定义其 uri 时使用了正则表达式模式(包括~,~*,但不包括^~),则 proxy_pass 之后必须不能使用 uri; 即不能有 / ,用户请求时传递的uri将直接附加至后端服务器之后。
为什么会报错:有太多选择性了,不允许你替换!
3.3 实战:指定 location 实现反向代理 动静分离
静态
动态
服务器
location ~* /api {proxy_pass http://192.168.44.30;
}location ~* \.(jpg|png|html|gif|txt|mp4)$ {proxy_pass http://192.168.44.50;
}
测试:
3.4 反向代理示例:缓存功能
缓存功能默认关闭,需要开启
proxy_cache zone_name | off; 默认off
#指明调用的缓存,或关闭缓存机制;Context:http, server, location
#zone_name 表示缓存的名称.需要由proxy_cache_path事先定义proxy_cache_key string;
#缓存中用于“键”的内容,默认值:proxy_cache_key $scheme$proxy_host$request_uri;proxy_cache_valid [code ...] time;
#定义对特定响应码的响应内容的缓存时长,定义在http{...}中示例:proxy_cache_valid 200 302 10m;proxy_cache_valid 404 1m;proxy_cache_path;
#定义可用于proxy功能的缓存;Context:http 必须放在http语句中
proxy_cache_path path [levels=levels] [use_temp_path=on|off]
keys_zone=zone_name:size [inactive=time] [max_size=size] [manager_files=number]
[manager_sleep=time] [manager_threshold=time] [loader_files=number]
[loader_sleep=time] [loader_threshold=time] [purger=on|off]
[purger_files=number] [purger_sleep=time] [purger_threshold=time];#示例:在http配置定义缓存信息proxy_cache_path /var/cache/nginx/proxy_cache #定义缓存保存路径,proxy_cache会自动创建levels=1:2:2 #定义缓存目录结构层次,1:2:2可以生成2^4x2^8x2^8=2^20=1048576个目录keys_zone=proxycache:20m #指内存中缓存的大小,主要用于存放key和metadata(如:使用次数),一般1M可存放8000个左右的keyinactive=120s #缓存有效时间 max_size=10g; #最大磁盘占用空间,磁盘存入文件内容的缓存空间最大值#调用缓存功能,需要定义在相应的配置段,如server{...};或者location等
proxy_cache proxycache;
proxy_cache_key $request_uri; #对指定的数据进行MD5的运算做为缓存的key
proxy_cache_valid 200 302 301 10m; #指定的状态码返回的数据缓存多长时间
proxy_cache_valid any 1m; #除指定的状态码返回的数据以外的缓存多长时间,必须设置,否则不会缓存proxy_cache_use_stale error | timeout | invalid_header | updating | http_500 | http_502 | http_503 | http_504 | http_403 | http_404 | off ; #默认是off
#在被代理的后端服务器出现哪种情况下,可直接使用过期的缓存响应客户端#示例
proxy_cache_use_stale error http_502 http_503;proxy_cache_methods GET | HEAD | POST ...;
#对哪些客户端请求方法对应的响应进行缓存,GET和HEAD方法总是被缓存
清理缓存:
方法1: rm -rf 缓存目录方法2: 第三方扩展模块ngx_cache_purge
添加首部字段:
nginx基于模块 ngx_http_headers_module 可以实现对后端服务器响应给客户端的报文中添加指定的响应首部字段
Syntax: add_header name value [always];
Default;
Context: http,server,location,if in location#添加响应报文的自定义首部:
add_header name value [always];#示例:
add_header X-Via $server_addr; #当前nginx主机的IP
add_header X-Cache $upstream_cache_status; #是否缓存命中
add_header X-Accel $server_name; #客户访问的FQDNadd_header X-Via
add_header X-Cache
add_header X-Accel
add_header X-Via $server_addr;add_header X-Cache $upstream_cache_status;add_header X-Accel $server_name;
3.5 实现反向代理客户端IP透传
单机去穿: httpd
架构:
查看日志:未添加之前的格式
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; #添加客户端IP和反向代理服务器IP到请求报文头部proxy_set_header X-Real-IP $remote_addr;
#只添加客户端IP到请求报文头部,转发至后端服务器
在日志格式里面添加:
查看日志:添加之后的格式
显示了真实的访问主机的ip地址
多机去穿: nginx
架构:
7-2
7-3
测试一下:代理没有问题
3.6 http反向代理负载均衡
Nginx 可以将客户端的请求转发至单台后端服务器,但是无法转发至特定的一组的服务器,而且不能对后端服务器提供相应的服务器状态监测,Nginx 可以基于 ngx_http_upstream_module 模块提供服务器分组转发、权重分配、状态监测、调度算法等高级功能。
配置方式:
server address [parameters];
#配置一个后端web服务器,配置在 upstream 内,至少要有一个 server 服务器配置。#server 支持的 parameters 如下:
weight=number #设置权重,默认为1,实现类似于LVS中的WRR,WLC等max_conns=number #给当前后端server设置最大活动链接数,默认为0表示没有限制max_fails=number #后端服务器的下线条件,当客户端访问时,对本次调度选中的后端服务器连续进行检测多少次,如果都失败就标记为不可用,默认为1次,当客户端访问时,才会利用TCP触发对探测后端服务器健康性检查,而非周期性的探测fail_timeout=time #后端服务器的上线条件,对已经检测到处于不可用的后端服务器,每隔此时间间隔再次进行检测是否恢复可用,如果发现可用,则将后端服务器参与调度,默认为10秒backup #设置为备份服务器,当所有后端服务器不可用时,才会启用此备用服务器 sorry server 自己不能转自己down #标记为 down 状态resolve #当 server 定义的是主机名的时候,当A记录发生变化会自动应用新IP而不用重启Nginx
单台实现负载均衡
在主配置里面:
测试:
这个就是轮询算法
当其中一台挂掉,就不去访问他了,直接跳过
那是因为 nginx 有检测机制 健康性检测 就不去这台机了
调度算法:
1. 轮询 一人一次
2. 加权轮询
3. ip hash
4. url hash
5. cookie hash
6.最少连接数
7.fair 根据响应时间
hash KEY [consistent];
#基于指定请求报文中首部字段或者URI等key做hash计算,使consistent参数,将使用ketama一致性hash算法,适用于后端是Cache服务器(如varnish)时使用,consistent定义使用一致性hash运算,一致性hash基于取模运算hash $request_uri consistent; #基于用户请求的uri做hash
hash $cookie_sessionid #基于cookie中的sessionid这个key进行hash调度,实现会话绑定ip_hash;
#源地址hash调度方法,基于的客户端的 remote_addr (源地址IPv4的前24位或整个IPv6地址)做hash计算,以实现会话保持least_conn;
#最少连接调度算法,优先将客户端请求调度到当前连接最少的后端服务器,相当于LVS中的WLC
操作:
加权轮询
理解字段含义:
① max_conns
② backup 设置备份服务器
hash算法
对文件进行hash运算,算文件得出一个值,修改文件,值就不一样了
ip hash
$remote_addr 客户端真实ip
修改权重之后,会有可能改变
uri hash
$request_uri
又变了回去:
cookie hash 保持会话
也是固定的:
最少连接数
least_conn
fair
此种算法可以依据页面大小和加载时间长短智能的进行负载均衡,也就是根据后端服务器的响应时间来分配请求,响应时间短的优先分配。
stream 服务模块:
实现反向代理功能,包括TCP协议代理 是四层模块
redis 是一个数据库
7-3
7-5
7-2 配置
未开redis 可以调度
四层代理和七层代理的区别:
4层是指传输层的 TCP/UDP 协议
7层是指应用层的 HTTP 协议
代理原理:
4层代理:使用 NAT(Network Address Translation)技术,即网络地址转换。即请求进来的时候,nginx 只修改数据包里面的目标IP、源IP、端口,然后就直接把数据包发给目标服务器(即nginx不知道请求的具体内容),目标服务器处理完成后,发给 nginx,nginx 数据包再做一次类似的修改,就返回给请求的客户端了。
7层代理:nginx 读取并解析 Http 请求内容,然后将具体内容(请求行、请求头、空行、请求数据)转发到相应的服务器,转发的过程是:建立和目标机器的连接,然后转发请求,收到响应数据再转发给请求客户端。