rewrite 模块
return 指令
该指令用于返回内容或者重定向
该指令有3种格式
return 状态码 [内容]; # 返回内容
return 状态码 URL; # 用于重定向
return URL; # 用于重定向,默认使用302临时重定向
上下文:server,location,if
error_page 指令
该指令用于当遇到404,500这样的状态码时进行重定向。
格式:
error_page code [=[response]] uri;
上下文:http,server,location,if in location
示例:
error_page 404 /404.html; # 找不到页面时跳转到404.html
error_page 500 502 503 504 /50x.html # 添加了多个状态码,跳转到50x.html
error_page 404 =200 /empty.gif #跳转到一张图片,并修改状态码为200
error_page 404 = /404.php # 跳转到404.php,状态码改为200
error_page 404 =301 http://abc.com/notfound.html #表示找不到时就永久重定向为abc.com/notfound.html
# 跳转到上游服务
location / {
error_page 404 = @notfound;
}
location @notfound {
proxy_pass http://notfound;
}
注意,error_page最后接的是uri地址而不是文件路径。
假如设置了
server_name zbpblog.com;
root /var/www;
error_page 404 /404.html;
当出现404时会跳转到 http://zbpblog.com/404.html,映射到的是/var/www/404.html这个文件
如果写成 error_page 404 404.html
当访问 http://zbpblog.com/sss/ddd 出现404时,他会跳到 http://www.abc.com/sss/ddd/404.html
如果error_page指令失效请试试设置:
proxy_intercept_errors on;
fastcgi_intercept_errors on;
小实验:
server {
listen 8080;
server_name return.zbpblog.com;
root /var/www/html;
access_log logs/access.log main;
error_page 404 /404.html;
#return 405;
location / {
return 404 "Not Found";
}
}
/var/www/html目录中放置了3个文件 index.html/test.html/404.html,里面内容分别为 “index”、“测试内容”、“找不到页面”
测试结果如下:
访问 http://return.zbpblog.com:8080/test.html
Not Found
访问 http://return.zbpblog.com:8080/
Not Found
访问 http://return.zbpblog.com:8080/sss
Not Found
说明走的是 location / {return 404 "Not Found";},而不是error_page;
就算找得到的页面也会返回Not Found
将return 404 "Not Found";注释
server {
listen 8080;
server_name return.zbpblog.com;
root /var/www/html;
access_log logs/access.log main;
error_page 404 /404.html;
#return 405;
location / {
#return 404 "Not Found";
}
}
访问 http://return.zbpblog.com:8080/test.html
“测试内容”
访问 http://return.zbpblog.com:8080/
“index”
访问 http://return.zbpblog.com:8080/sss
“找不到页面”
说明跳转到404.html
将return 405和return 404 "Not Found"注释打开:
server {
listen 8080;
server_name return.zbpblog.com;
root /var/www/html;
access_log logs/access.log main;
error_page 404 /404.html;
return 405;
location / {
return 404 "Not Found";
}
}
无论访问什么都返回405,因为先执行了server的return,之后的代码就都不会执行了。
rewrite 指令
格式 rewrite regex replacement [flag];
上下文:server,location,if
当replacement以http://或https://或者$schema开头,会直接返回302重定向
4种flag:
last:用replacement这个URI进行新的location匹配并停止继续处理当前区块所有接下来的语句。重写得到的新URL会重新匹配所有location语句,以进行进一步处理。
break:用replacement这个URI进行新的location匹配并停止继续处理当前区块所有接下来的语句。重写得到的新URL不会重新匹配location语句。
redirect:返回302临时重定向。
permanent:返回301永久重定向。
小实验:
/var/www/html目录结构如下:
|-index.html
|-first
|-1.txt # "txt1"
|-second
|-2.txt # "txt2"
|-third
|-3.txt # "txt3"
server {
listen 8080;
server_name return.zbpblog.com;
root /var/www/html;
access_log logs/access.log main;
error_page 404 /404.html;
autoindex on; # 开启浏览目录的功能
#
# 不同的location
#
}
情景1:
### 处写法1:
location /first {
rewrite /first(.*) /second$1 redirect;
}
location /second {
rewrite /second(.*) /third$1 redirect;
}
访问 http://return.zbpblog.com:8080/first
浏览器url栏最终url为third
F12查看一共3条请求,文件名和状态码为first 301,second 302,third 200
最终显示的是third目录的目录结构。
访问 http://return.zbpblog.com:8080/first/3.txt
浏览器url栏最终url为third/3.txt
F12查看一共3条请求,文件名和状态码为first/3.txt 302,second/3.txt 302,third/3.txt 200
最终显示的是/third/3.txt的内容
情景2:
### 处写法2:
location /first {
rewrite /first(.*) /second$1 permanent;
}
location /second {
rewrite /second(.*) /third$1 permanent;
}
访问 http://return.zbpblog.com:8080/first
浏览器url栏最终url为third
F12查看一共3条请求,状态码全为301,301,200
最终显示的是third目录的目录结构
访问 http://return.zbpblog.com:8080/first/3.txt
浏览器url栏最终url为third/3.txt
F12查看一共3条请求,文件名和状态码为first/3.txt 301,second/3.txt 301,third/3.txt 200
最终显示的是/third/3.txt的内容
情景3:
### 处写法3:
location /first {
rewrite /first(.*) /second$1;
}
location /second {
rewrite /second(.*) /third$1;
}
访问 http://return.zbpblog.com:8080/first
浏览器url栏不变
F12查看一共1条请求,first 200
但是已经重定向到third目录
访问 http://return.zbpblog.com:8080/first/3.txt
浏览器url栏不变
F12查看一共1条请求,first/3.txt 200
但实际上显示的是third/3.txt的内容。
情景4:
location /first {
rewrite /first(.*) /second$1 break;
return 200 "xxx1";
}
location /second {
rewrite /second(.*) /third$1;
}
访问 http://return.zbpblog.com:8080/first/3.txt
浏览器url栏不变
F12查看一共1条请求,first/3.txt 404
first/3.txt会跳到second/3.txt 但由于break,/second/3.txt不会重新匹配location /second,所以不会跳到/third/3.txt。second没有3.txt所以404
情景5:
### 处写法5:
location /first {
rewrite /first(.*) /second$1 last;
return 200 "xxx1";
}
location /second {
rewrite /second(.*) /third$1;
}
访问 http://return.zbpblog.com:8080/first/3.txt
浏览器url栏不变
F12查看一共1条请求,first/3.txt 200
first/3.txt会跳到second/3.txt 再跳到third/3.txt。
last和break会停止运行当前块中之后代码的运行(如return 200 "xxx1"),但last会在跳转后重新匹配所有的location,而break不会。
如果rewrite不加flag,那么会运行完该区块下所有的指令后,再对跳转后新的url重新匹配所有的location。
使用last和break和不加flag,虽然跳转了,但浏览器上显示的url不变。permanent和redirect会变。
情景6:
### 写法6:
location /first {
rewrite /first(.*) /second$1 last;
return 200 "first";
}
location /second {
rewrite /second(.*) /third$1 break;
return 200 "second";
}
location /third {
return 200 "third";
}
访问 http://return.zbpblog.com:8080/first/3.txt
浏览器url栏不变
F12查看一共1条请求,first/3.txt 200
first/3.txt会跳到second/3.txt 再跳到third/3.txt
过程为: location /first匹配到,跳转到second/3.txt,由于last所以return 200 "first"不执行并且对second/3.txt重新匹配一次全部location;
location /second块匹配到,跳转到third/3.txt,由于break所以return 200 "second"不执行并且不会对second/3.txt重新匹配一次全部location;
所以location /third块中的return 200 "third"也不会执行。
if 指令
该if指令是专门用来判断变量的。
PS if和()间有空格,没有会报错。
格式 if (condition){...}
上下文:server,location
if指令的表达式:
1.检查变量是否为空或者是否为0
2.将变量与字符串做匹配,使用=或!=
3.将变量和正则做匹配,使用~表示匹配,!~不匹配;~*忽略大小写匹配,!~*忽略大小不匹配
4.检查文件是否存在,使用-f或!-f
5.检查目录是否存在,-d或!-d
6.检查文件、目录、软链接是否存在,-e或!-e
7.检查是否为可执行文件,使用-x或者!-x
示例:
if($http_user_agent ~ MSIE){ #使用正则匹配,如果变量中有MSIE这个字符串,即浏览器是IE,就做重定向。
rewrite ^(.*?)$ /msie/$1 break;
}
if($http_cookie ~* "id=([^;]+)") { # 如果匹配到$http_cookie中含有id=xxx的内容,就定义一个变量$id为分组匹配内的内容
set $id $1;
}
if($request_method = POST){
return 405;
}
if($slow){
limit_rate 10k;
}
if($invalid_referer){ #用于防盗链
return 403;
}
location 指令
格式:location [=|~|~*|^~] uri {...}
上下文:server,location
所以 location可以嵌套location
location匹配规则:
常规匹配:又叫做前缀匹配,如 location /test {...} 可以匹配/test,/test/a,/test/1.html等,只要URI中是以/test开头的都能匹配到。
= :精确匹配 location /test {...} 只能匹配 /test
^~:前缀匹配上后就不再进行正则匹配。就当他是一个前缀匹配即可。
~和~*:对URI正则匹配
@:用于内部跳转的命名location
示例:
# 1
location ~ /Test1/$ {
return 200 "first regular expressions mathc!";
}
# 2
location ~* /Test1/(\w+)$ {
return 200 "longest regular expressions match!";
}
# 3
location ^~ /Test1/ {
return 200 "stop regular expression match!";
}
# 4
location /Test1/Test2 {
return 200 "longest prefix string match!";
}
# 5
location /Test1 {
return 200 "prefix string match";
}
# 6
location = /Test1 {
return 200 "exact match!";
}
有以下url:
/Test1 # 匹配5,6
/Test1/ # 匹配1,3,5
/Test1/Test2 # 匹配2,3,4,5
/Test1/Test2/ # 匹配3,4,5
/test1/Test2 # 匹配2
上面除了/test1/Test2这个url是明确只匹配2号location的,其他都匹配多个。那么它是有优先级的,而且不是单纯的按顺序来决定优先级的。
优先级规则:
^~和常规匹配都属于前缀匹配。
=精确匹配最先进行,前缀匹配次之,正则匹配最后。但是精确匹配成功则不会再往下匹配前缀或者正则;但前缀匹配成功后会再进行正则匹配(^~匹配成功则不会再进行正则匹配),如果正则匹配成功则使用正则匹配的location而不使用前缀匹配的location,如果没有正则匹配成功则使用最长的前缀匹配。
如果多个前缀匹配都符合,则长的优先级更高。
如果多个正则匹配都符合,则最先出现的正则优先级更高。
根据以上则:
/Test1 匹配6,精确匹配
/Test1/ 匹配3,过程:先进行前缀匹配(3,5),3比5长,所以3匹配成功,由于3使用^~,所以1正则就不再去匹配。
/Test1/Test2 匹配2,过程:先进行前缀匹配(3,4,5),4最长,再进行正则匹配,2匹配成功,所以不使用前缀匹配4而使用2
/Test1/Test2/ 匹配4,过程:先进行前缀匹配(3,4,5),4最长,再进行正则匹配,没有正则能匹配的上。
/test1/Test2 # 匹配2,只有2是大小写都匹配