# to_test直接访问test目录
if ($uri ~ ^/break/to_test/(.*)) {
rewrite ^/break/to_test/(.*) /$1 break;
root /Users/webroot/test;
# to_last改写到last,重走匹配
rewrite ^/break/to_last/(.*) /last/$1 last;
# uri被重写, 则设置一个变量
if ($uri !~ ^/break/(.*)) {
set $is_rewrite 1;
location /last/ {
rewrite ^/last/(.*) /test/$1 last;
location /test/ {
log_format
myformat
'is_rewrite='
$is_rewrite
;
server
{
listen
9999
;
rewrite_log
on
;
access_log
/
Users
/
webroot
/
access
.log
myformat
;
error_log
/
Users
/
webroot
/
error
.log
notice
;
root
/
Users
/
webroot
/
;
location
/
break
/
{
# to_test直接访问test目录
if
(
$uri
~
^
/
break
/
to_test
/
(
.
*
)
)
{
rewrite
^
/
break
/
to_test
/
(
.
*
)
/
$
1
break
;
root
/
Users
/
webroot
/
test
;
}
# to_last改写到last,重走匹配
rewrite
^
/
break
/
to_last
/
(
.
*
)
/
last
/
$
1
last
;
# uri被重写, 则设置一个变量
if
(
$uri
!
~
^
/
break
/
(
.
*
)
)
{
set
$is_rewrite
1
;
}
}
location
/
last
/
{
rewrite
^
/
last
/
(
.
*
)
/
test
/
$
1
last
;
}
location
/
test
/
{
}
}
执行:这次第一个If语句成功匹配,if内的rewrite可以成功执行,将/break/to_test/x重写至了/x,break将导致该rewrite之后的所有rewrite将被忽略,但代码将继续向下执行(这很重要),因此接下来的root指令会得到执行,root被直接指向了/Users/webroot/test目录,其覆盖了server中定义的默认root。接下来遇到第二个rewrite指令时将直接跳过(因为之前的break)。
按照规则,接下来的if语句应该可以得到执行,并且也应满足条件,is_rewrite变量将会被设置为1,然而现实却是if没有执行,”坑”来了!
网上的资料都会说break/last之后的rewrite指令不会被执行,但是为什么导致了if不执行呢?其实,这种说法是”以讹传讹”的错误结论,按照官方的说法break和last终止的是
ngx_http_rewrite_module模块的执行,这个模块负责了像if、set、return、rewrite这些语法的解析和执行,因此不仅仅是rewrite失效,后续出现的这些语法都会失效!
官方文档地址:
http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#break
,break的相关说明:
Stops processing the current set of
ngx_http_rewrite_module
directives.
If a directive is specified inside the
location
, further processing of the request continues in this location.
注意,停止的是the current set of
ngx_http_rewrite_module
的执行,而不是Stops processing。因此,指令将继续下来执行,而属于ngx_http_rewrite_module的指令将被跳过。
这里贴一下rewrite日志,看一下究竟。
首先是请求/break/x:
2017/06/12 17:55:14 [notice] 29778#0: *790 "^/break/to_test/(.*)" does not match "/break/x", client: 127.0.0.1, server: , request: "GET /break/x HTTP/1.1", host: "localhost:9999"
2017/06/12 17:55:14 [notice] 29778#0: *790 "^/break/to_last/(.*)" does not match "/break/x", client: 127.0.0.1, server: , request: "GET /break/x HTTP/1.1", host: "localhost:9999"
2017/06/12 17:55:14 [notice] 29778#0: *790 "^/break/(.*)" matches "/break/x", client: 127.0.0.1, server: , request: "GET /break/x HTTP/1.1", host: "localhost:9999"
2017
/
06
/
12
17
:
55
:
14
[
notice
]
29778
#0: *790 "^/break/to_test/(.*)" does not match "/break/x", client: 127.0.0.1, server: , request: "GET /break/x HTTP/1.1", host: "localhost:9999"
2017
/
06
/
12
17
:
55
:
14
[
notice
]
29778
#0: *790 "^/break/to_last/(.*)" does not match "/break/x", client: 127.0.0.1, server: , request: "GET /break/x HTTP/1.1", host: "localhost:9999"
2017
/
06
/
12
17
:
55
:
14
[
notice
]
29778
#0: *790 "^/break/(.*)" matches "/break/x", client: 127.0.0.1, server: , request: "GET /break/x HTTP/1.1", host: "localhost:9999"
第1行日志代表了第一个If和/break/to_test/(.*)匹配失败,第2行日志代表了第二个rewrite /break/to_last/(.*)匹配失败,第3行日志判断!~ ^/break/(.*)得到执行但条件并没有成立,这是因为前面的rewrite都没有匹配成功,last和break并没有生效,因此if指令可以被ngx_http_rewrite_module模块正常执行。
接下来请求/break/to_test/x:
2017/06/12 17:57:49 [notice] 29778#0: *792 "^/break/to_test/(.*)" matches "/break/to_test/x", client: 127.0.0.1, server: , request: "GET /break/to_test/x HTTP/1.1", host: "localhost:9999"
2017/06/12 17:57:49 [notice] 29778#0: *792 "^/break/to_test/(.*)" matches "/break/to_test/x", client: 127.0.0.1, server: , request: "GET /break/to_test/x HTTP/1.1", host: "localhost:9999"
2017/06/12 17:57:49 [notice] 29778#0: *792 rewritten data: "/x", args: "", client: 127.0.0.1, server: , request: "GET /break/to_test/x HTTP/1.1", host: "localhost:9999"
2017
/
06
/
12
17
:
57
:
49
[
notice
]
29778
#0: *792 "^/break/to_test/(.*)" matches "/break/to_test/x", client: 127.0.0.1, server: , request: "GET /break/to_test/x HTTP/1.1", host: "localhost:9999"
2017
/
06
/
12
17
:
57
:
49
[
notice
]
29778
#0: *792 "^/break/to_test/(.*)" matches "/break/to_test/x", client: 127.0.0.1, server: , request: "GET /break/to_test/x HTTP/1.1", host: "localhost:9999"
2017
/
06
/
12
17
:
57
:
49
[
notice
]
29778
#0: *792 rewritten data: "/x", args: "", client: 127.0.0.1, server: , request: "GET /break/to_test/x HTTP/1.1", host: "localhost:9999"
第1行日志代表了第一个If匹配成功,因此进入了if。第2行日志代表了if内的rewrite匹配成功(指定了break),因此第3行日志打印URI被改写为/x。接下来还有1个rewrite /break/to_last/(.*)并没有打印match日志,后续的if也没有打印,说明rewrite的break生效了,符合预期。
接下来请求/break/to_last/x:
2017/06/12 18:03:57 [notice] 29778#0: *794 "^/break/to_test/(.*)" does not match "/break/to_last/x", client: 127.0.0.1, server: , request: "GET /break/to_last/x HTTP/1.1", host: "localhost:9999"
2017/06/12 18:03:57 [notice] 29778#0: *794 "^/break/to_last/(.*)" matches "/break/to_last/x", client: 127.0.0.1, server: , request: "GET /break/to_last/x HTTP/1.1", host: "localhost:9999"
2017/06/12 18:03:57 [notice] 29778#0: *794 rewritten data: "/last/x", args: "", client: 127.0.0.1, server: , request: "GET /break/to_last/x HTTP/1.1", host: "localhost:9999"
2017/06/12 18:03:57 [notice] 29778#0: *794 "^/last/(.*)" matches "/last/x", client: 127.0.0.1, server: , request: "GET /break/to_last/x HTTP/1.1", host: "localhost:9999"
2017/06/12 18:03:57 [notice] 29778#0: *794 rewritten data: "/test/x", args: "", client: 127.0.0.1, server: , request: "GET /break/to_last/x HTTP/1.1", host: "localhost:9999"
2017
/
06
/
12
18
:
03
:
57
[
notice
]
29778
#0: *794 "^/break/to_test/(.*)" does not match "/break/to_last/x", client: 127.0.0.1, server: , request: "GET /break/to_last/x HTTP/1.1", host: "localhost:9999"
2017
/
06
/
12
18
:
03
:
57
[
notice
]
29778
#0: *794 "^/break/to_last/(.*)" matches "/break/to_last/x", client: 127.0.0.1, server: , request: "GET /break/to_last/x HTTP/1.1", host: "localhost:9999"
2017
/
06
/
12
18
:
03
:
57
[
notice
]
29778
#0: *794 rewritten data: "/last/x", args: "", client: 127.0.0.1, server: , request: "GET /break/to_last/x HTTP/1.1", host: "localhost:9999"
2017
/
06
/
12
18
:
03
:
57
[
notice
]
29778
#0: *794 "^/last/(.*)" matches "/last/x", client: 127.0.0.1, server: , request: "GET /break/to_last/x HTTP/1.1", host: "localhost:9999"
2017
/
06
/
12
18
:
03
:
57
[
notice
]
29778
#0: *794 rewritten data: "/test/x", args: "", client: 127.0.0.1, server: , request: "GET /break/to_last/x HTTP/1.1", host: "localhost:9999"
第1行日志说明If /break/to_test/(.*)匹配失败,因此没有进入If。第2行日志说明rewrite /break/to_last/(.*)匹配成功(指定了last),因此第3行日志打印URI被改写为/last/x。代码继续向下执行到最后一个If,因为之前rewrite last的原因If将不会被执行,因此没有相关日志打印。location执行完成,因为last原因URI被Nginx重新执行解析,这次匹配了location /last/,其内部的rewrite直接将/last/x重写为/test/x,因为其last的原因又再次被nginx重新执行解析。最终,与location /test匹配,直接读取server中的root路径/Users/webroot下的/test/x文件,请求结束。
掌握了rewrite可以做很多事情,玩的愉快。