Nginx HTTP模块篇 rewrite模块 (十一)

本文详细介绍了Nginx中return指令的返回内容和重定向功能,error_page指令处理错误状态码的策略,以及rewrite模块的正则表达式重写、flag选项和实际应用场景。通过实例演示了不同场景下的工作原理和优先级规则。
摘要由CSDN通过智能技术生成

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是大小写都匹配

本文转载自: 张柏沛IT技术博客 > Nginx HTTP模块篇 rewrite模块 (十一)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值