其实rewrite指令和上一篇说的if/set/return/break之类的没多大差别,但是rewrite用起来相对复杂,我就把他单独放到了这里。想要弄懂nginx的脚本引擎需要先明白处理request的十一个处理阶段,不懂的话先去搜一下看看,网上很多。先说一下rewrite的用法吧。
rewrite regex replacement [flag];
regex:用来匹配uri的正则表达式。
replacement:匹配成功后用这个字段替换请求的uri。
上面这两个没什么可说的,简单明白,看一下flag,flag可以取的值如下:
last:当前指令执行完之后不在执行之后的指令,如果是在location块里这个请求会重新回到NGX_HTTP_FIND_CONFIG_PHASE阶段用新的uri寻找新location。
break:当前指令执行完之后不在执行之后的指令。
redirect:返回302重定向。
permanent 返回301重定向。
redirect和permanent比较简单,就不用说了,主要是区分last和break,这两个指令用在server块里没什么区别,但是用在location块里就要注意了,下面这个配置是我把官方文档上的例子拿过来改的。
location /download/ { rewrite ^(/download/)(.*)\..*$ $1/mp3/$2.mp3 break; rewrite ^(/download/)(.*)\..*$ $1/mp3/$2.ra break; return 403; }
如果把break换成last,并且匹配上了这条指令修改uri之后,请求会重新回到NGX_HTTP_FIND_CONFIG_PHASE阶段,因为uri的前缀没变会继续匹配到这个location,再执行rewrite,造成死循环,最终返回500错误。
我觉得官方文档上的例子并不会造成500错误,是我理解的不对还是他举的例子不对?传送门http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite
这几个标志都会执行如下的代码,结束当前的脚本。
if (last) {
code = ngx_http_script_add_code(lcf->codes, sizeof(uintptr_t), ®ex);
if (code == NULL) {
return NGX_CONF_ERROR;
}
*code = NULL;
}
不同的是break的情况,break会额外执行如下的代码
if (code->uri) {
r->internal = 1;
r->valid_unparsed_uri = 0;
if (code->break_cycle) {
r->valid_location = 0;
r->uri_changed = 0;
} else {
r->uri_changed = 1;
}
}
把r->uri_changed置位,到了NGX_HTTP_POST_REWRITE_PHASE会检查这个标志,如果不为0就会跳回NGX_HTTP_FIND_CONFIG_PHASE阶段,这就是break标志和last标志的不同。