nginx的rewrite指令中break flag疑问

nginx 配置

server {
    listen 8080 default_server ;
    root /opt/website/write ;
    rewrite_log on ;
    location /location1/ {
        rewrite /location1/(.*) /test/$1 last ;
        return 200 "location1\r\n" ;
    }
    location /location2/ {
        rewrite /location2/(.*) /test/$1 break ;
        return 200 "location2\r\n" ;
    }
    location /test/ {
        return 200 "test\r\n" ;
    }
    location / {
        return 200 "null\r\n" ;
    }
}
  • 创建目录和index.html

# mkdir -p /opt/website/write/{location1,location2,test}

# ls /opt/website/write/|awk '{print $1".index" > "/opt/website/write/"$1"/index.html"}'

  • 测试:

[root@centos-81 ~]# curl -s 192.168.1.81:8080/location2/
test

[root@centos-81 ~]# curl -s 192.168.1.81:8080/location2/index.html
test.index

疑问:

  • 对第一个请求结果有疑问,照着官方文档描述,break 不会跳出location层级,应该直接寻找 test/目录下的index.html,理论上返回的是 test.index。不知道是啥原因返回了 test

  • 在第二个请求中也证明了是寻找 /test/目录下的文件,而不是跳出location。

不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 给你找了一篇非常好的博客,你可以看看是否有帮助,链接:nginx反向代理和rewrite进行解决跨域问题 去掉url中的一部分字符串,通过nginx正则生成新的url
  • 除此之外, 这篇博客: nginx(一)中的 rewrite中的break和last 部分也许能够解决你的问题, 你可以仔细阅读以下内容或者直接跳转源博客中阅读:

    两个指令用法相同,但含义不同,需要放到rewrite规则的末尾,用来控制重写后的链接是否继续被nginx配置执行(主要是rewrite、return指令)。

    示例1(连续两条rewrite规则):

    server{
        listen 80; 
        server_name test.com;
        root /tmp/123.com;
    
        rewrite /1.html /2.html ;
        rewrite /2.html /3.html ;
        
    }
    

    当我们请求1.html时,最终访问到的是3.html,两条rewrite规则先后执行。
    break和last在location {}外部
    格式:rewrite xxxxx break;

    示例2(增加break):

    server{
        listen 80; 
        server_name test.com;
        root /tmp/123.com;
    
        rewrite /1.html /2.html break;
        rewrite /2.html /3.html;
    }
    

    当我们请求1.html时,最终访问到的是2.html
    说明break在此示例中,作用是不再执行break以下的rewrite规则。

    但,当配置文件中有location时,它还会去执行location{}段的配置(请求要匹配该location)。

    示例3(break后面还有location段):

    server{
        listen 80; 
        server_name test.com;
        root /tmp/123.com;
    
        rewrite /1.html /2.html break;
        rewrite /2.html /3.html;
        location /2.html {
            return 403;
        }
    }
    

    当请求1.html时,最终会返回403状态码,说明它去匹配了break后面的location{}配置。

    以上2个示例中,可以把break替换为last,它们两者起到的效果一模一样。
    当break和last在location{}里面
    示例4(什么都不加):

    server{
        listen 80; 
        server_name test.com;
        root /tmp/123.com;
        
        location / {
            rewrite /1.html /2.html;
            rewrite /2.html /3.html;
        }
        location /2.html
        {
            rewrite /2.html /a.html;
        }
        location /3.html
        {
            rewrite /3.html /b.html;
        }
    }
    

    当请求/1.html,最终将会访问/b.html,连续执行location /下的两次rewrite,跳转到了/3.html,然后又匹配location /3.html

    示例5(增加break):

    server{
        listen 80; 
        server_name test.com;
        root /tmp/123.com;
        
        location / {
            rewrite /1.html /2.html break;
            rewrite /2.html /3.html;
        }
        location /2.html
        {
            rewrite /2.html /a.html;
        }
        location /3.html
        {
            rewrite /3.html /b.html;
        }
    }
    

    当请求/1.html,最终会访问/2.html
    在location{}内部,遇到break,本location{}内以及后面的所有location{}内的所有指令都不再执行。

    示例6(增加last):

    server{
        listen 80; 
        server_name test.com;
        root /tmp/123.com;
        
        location / {
            rewrite /1.html /2.html last;
            rewrite /2.html /3.html;
        }
        location /2.html
        {
            rewrite /2.html /a.html;
        }
        location /3.html
        {
            rewrite /3.html /b.html;
        }
    }
    

    当请求/1.html,最终会访问/a.html
    在location{}内部,遇到last,本location{}内后续指令不再执行,而重写后的url再次从头开始,从头到尾匹配一遍规则。

    结论

    • 当rewrite规则在location{}外,break和last作用一样,遇到break或last后,其后续的rewrite/return语句不再执行。但后续有location{}的话,还会近一步执行location{}里面的语句,当然前提是请求必须要匹配该location。
    • 当rewrite规则在location{}里,遇到break后,本location{}与其他location{}的所有rewrite/return规则都不再执行。
    • 当rewrite规则在location{}里,遇到last后,本location{}里后续rewrite/return规则不执行,但重写后的url再次从头开始执行所有规则,哪个匹配执行哪个。

如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^