nginx url 重写:break 和 last 之间的区别

64 rewrite nginx

我不明白 break 和 last (重写标志)之间的区别。文档相当深奥。我试图在我的一些配置中在两者之间切换,但我无法发现任何行为差异。有人可以更详细地解释这些标志吗?最好有一个例子,当将一个标志翻转到另一个时显示不同的行为。

Pot*_*thu 71

OP更喜欢一个例子。另外,@minaev 所写的只是故事的一部分!所以,我们开始...

示例 1:无(中断或最后)标志

server {
    server_name example.com;
    root 'path/to/somewhere';

    location / {
        echo 'finally matched location /';
    }

    location /notes {
        echo 'finally matched location /notes';
    }

    location /documents {
        echo 'finally matched location /documents';
    }

    rewrite ^/([^/]+.txt)$ /notes/$1;
    rewrite ^/notes/([^/]+.txt)$ /documents/$1;
}
Run Code Online (Sandbox Code Playgroud)

结果:

# curl example.com/test.txt
finally matched location /documents
Run Code Online (Sandbox Code Playgroud)

解释:

对于rewrite,标志是可选的!

示例 2:外部位置块(break 或 last)

server {
    server_name example.com;
    root 'path/to/somewhere';

    location / {
        echo 'finally matched location /';
    }

    location /notes {
        echo 'finally matched location /notes';
    }

    location /documents {
        echo 'finally matched location /documents';
    }

    rewrite ^/([^/]+.txt)$ /notes/$1 break; # or last
    rewrite ^/notes/([^/]+.txt)$ /documents/$1; # this is not parsed
}
Run Code Online (Sandbox Code Playgroud)

结果:

# curl example.com/test.txt
finally matched location /notes
Run Code Online (Sandbox Code Playgroud)

解释:

外面的位置块,都breaklast在精确的方式表现...

  • 不再解析重写条件
  • Nginx 内部引擎进入下一阶段(搜索location匹配)

示例 3:内部位置块 - “break”

server {
    server_name example.com;
    root 'path/to/somewhere';

    location / {
        echo 'finally matched location /';
        rewrite ^/([^/]+.txt)$ /notes/$1 break;
        rewrite ^/notes/([^/]+.txt)$ /documents/$1; # this is not parsed
    }

    location /notes {
        echo 'finally matched location /notes';
    }

    location /documents {
        echo 'finally matched location /documents';
    }
}
Run Code Online (Sandbox Code Playgroud)

结果:

# curl example.com/test.txt
finally matched location /
Run Code Online (Sandbox Code Playgroud)

解释:

在位置块内,break标志将执行以下操作...

  • 不再解析重写条件
  • Nginx 内部引擎继续解析当前location

示例 4:内部位置块 - “last”

server {
    server_name example.com;
    root 'path/to/somewhere';

    location / {
        echo 'finally matched location /';
        rewrite ^/([^/]+.txt)$ /notes/$1 last;
        rewrite ^/notes/([^/]+.txt)$ /documents/$1;  # this is not parsed
    }

    location /notes {
        echo 'finally matched location /notes';
        rewrite ^/notes/([^/]+.txt)$ /documents/$1;  # this is not parsed, either!
    }

    location /documents {
        echo 'finally matched location /documents';
    }
}
Run Code Online (Sandbox Code Playgroud)

结果:

# curl example.com/test.txt
finally matched location /notes
Run Code Online (Sandbox Code Playgroud)

解释:

在位置块内,last标志将执行以下操作...

  • 不再解析重写条件
  • Nginx 内部引擎根据结果开始寻找另一个位置匹配rewrite
  • 不再解析重写条件,即使在下一个位置匹配时!

概括:

  • rewrite带有标志breaklast匹配的条件时,Nginx 将停止解析rewrites
  • 在位置块之外,使用breaklast,Nginx 执行相同的工作(不再处理重写条件)。
  • 在位置块内,使用break,Nginx 只会停止处理再重写条件
  • 在位置块中,使用last,Nginx 不再处理重写条件,然后开始寻找新的location块匹配!Nginx 也会忽略rewriteslocation块中的任何内容!

最后说明:

我错过了包含更多边缘情况(实际上是重写的常见问题,例如500 internal error)。但是,这超出了这个问题的范围。可能,示例 1 也超出了范围!

  • @CraigHicks 不,不会。重写规则具有更高的优先级,并且在匹配位置之前首先执行。 (3认同)
  • 在示例 1 中,如果将重写规则放在所有三个位置指令之上会有所不同吗? (2认同)
  • 这应该是最好的答案。参考这些示例并阅读 nginx 文档很容易理解。 (2认同)

min*_*aev 50

对于不同的位置,您可能有不同的重写规则集。当 rewrite 模块遇到 时last,它停止处理当前集合并再次传递重写请求以找到合适的位置(以及新的重写规则集)。如果规则以 结束break,重写也会停止,但重写的请求不会传递到另一个位置。

也就是说,如果有两个位置:loc1 和 loc2,并且在 loc1 中有一个重写规则将 loc1 更改为 loc2 并以 结尾last,则请求将被重写并传递到位置 loc2。如果规则以 结尾break,则它将属于位置 loc1。