ngx_http_rewrite_module模块用于使用pcre正则表达式更改请求URI、返回重定向和有条件地选择配置。此模块主要有下面几个指令:break,if,return,rewrite和set指令,这些指令按照以下顺序被执行:
- 首先按照顺序执行server上下文中的rewrite模块指令。
- 循环执行以下指令
- 依据请求的URI,匹配定义对应的location
- 按照顺序执行匹配到的location中的rewrite模块指令
- 如果请求被重写,将进入下一次的循环,但是循环的次数不能超过10次。
指令讲解
下面分别看看上面的每个指令:
break
停止执行 ngx_http_rewrite_module 的指令集,但是其他模块指令是不受影响的。
1 2 3
| Syntax: break; Default: — Context: server, location, if
|
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| server { listen 8080; break; return 200 "ok"; location = /testbreak { break; return 200 $request_uri; proxy_pass http://127.0.0.1:8080/other; } location / { return 200 $request_uri; } }
|
发送请求和得到的结果如下:
1 2
| curl 127.0.0.1:8080/testbreak /other
|
可以看到 返回 /other 而不是 /testbreak,说明 proxy_pass 指令还是被执行了,也就是说 其他模块的指令是不会被 break 中断执行的(proxy_pass是ngx_http_proxy_module的指令)
if
依据指定的条件决定是否执行 if 块语句中的内容。里面可以设置其他模块的指令,但是必须是if指令所在上下文中存在的指令。
1 2 3
| Syntax: if (condition) { ... } Default: — Context: server, location
|
if 中的几种 判断条件
- 一个
变量名,如果变量 $variable 的值为空字符串或者字符串”0”,则为false
变量与一个字符串的比较相等为(=) 不相等为(!=)
变量与一个正则表达式的模式匹配 操作符可以是(~ 区分大小写的正则匹配, ~*不区分大小写的正则匹配, !~``!~*,前面两者的非)
- 检测文件是否存在 使用
-f(存在) 和 !-f(不存在)
- 检测路径是否存在 使用
-d(存在) 和 !-d(不存在) 后面判断可以是字符串也可是变量
- 检测文件、路径、或者链接文件是否存在 使用
-e(存在) 和 !-e(不存在) 后面判断可以是字符串也可是变量
- 检测文件是否为可执行文件 使用
-x(可执行) 和 !-x(不可执行) 后面判断可以是字符串也可是变量
注意 上面 第1,2,3条被判断的必须是变量, 4, 5, 6, 7则可以是变量也可是字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| set $variable "0"; if ($variable) { break; }
if ( $http_host ~ "^star\.igrow\.cn$" ) { break; }
if ( "star" ~ "^star\.igrow\.cn$" ) { break; }
if ( !-f "/data.log" ) { break; }
if ( !-f $filename ) { break; }
|
return
停止处理并将指定的code码返回给客户端。在不发送响应头的情况下关闭连接则设置code码为444(这个是nginx特有的,不一定适用于其他的服务器)。
从0.8.42版开始,可以指定重定向URL(code码为301、302、303、307和308)或响应正文文本(不是前面的重定向或者444code码)。响应正文文本和重定向URL可以包含变量。在特殊情况下,可以将重定向URL指定为此服务器的本地URI,在这种情况下,重定向的完整URL是根据请求方案($scheme)和重定向指令中的server_name_in_redirect和port_in_redirect来形成。
此外,可以只设置URl参数,不过这样的指令返回的code码都是302.可以将代码为302。这样的参数以“http://”、“https://”或“$scheme”字符串开头。URL可以包含变量。
在版本0.7.51之前可以使用以下code码:204、400、402-406、408、410、411、413、416和500-504。
直到版本1.1.16和1.0.13,code码307才被视为重定向。
直到版本1.13.0,code码308才被视为重定向。
1 2 3 4 5
| Syntax: return code [text]; return code URL; return URL; Default: — Context: server, location, if
|
例子如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| location = /ok { return 200 "ok"; }
location = /redirect { return 302 http://www.baidu.com; }
location = /redirect { return http://www.baidu.com; }
|
rewrite
1 2 3
| Syntax: rewrite regex replacement [flag]; Default: — Context: server, location, if
|
如果指定的正则表达式与请求URI匹配,URI将会替换成replacement字符串。rewrite指令按照它们在配置文件中出现的顺序依次执行。可以使用flag终止指令的进一步处理。如果替换字符串以“http://”、 “https://” 或“$scheme”开头,则停止处理并将重定向返回到客户端。
这里先看俩个例子,然后在来说rewrite的四个flag
第一种情况 重写的字符串 带http://
1 2 3 4 5 6
| location / { rewrite /test1/(.*) http://www.$1.com; return 200 "ok"; }
|
在浏览器中输入
1
| 127.0.0.1:8080/test1/baidu
|
则临时重定向到 www.baidu.com,后面的 return 指令将没有机会执行.
第二种情况 重写的字符串 不带http://
1 2 3 4
| location / { rewrite /test1/(.*) www.$1.com; return 200 "ok"; }
|
发送请求和结果如下
1 2
| curl 127.0.0.1:8080/test1/baidu ok
|
此处没有带http:// 所以只是简单的重写。请求的 uri 由 /test1/baidu 重写为 www.baidu.com。因为会顺序执行 rewrite指令所以下一步执行return指令响应了ok
rewrite 的四个 flag
last
停止处理当前的ngx_http_rewrite_module的指令集,并开始搜索与更改后的URI相匹配的location;
break
停止处理当前的ngx_http_rewrite_module指令集,就像上面说的break指令一样;
redirect
返回302临时重定向。
permanent
返回301永久重定向。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
location / { rewrite ^/test1 /test2; rewrite ^/test2 /test3; }
location = /test2 { return 200 "/test2"; }
location = /test3 { return 200 "/test3"; }
|
发送请求和结果如下:
1 2
| curl 127.0.0.1:8080/test1 /test3
|
从上面可以看出,在第一个location中,将地址重写成/test3,也就是符合我们说的,如果没有flag时,就顺序执行,然后执行到最后一个时,就去搜索location,返回对应的结果。
last 与 break 的区别
last和break一样它们都会终止此location中其他它rewrite模块指令的执行,但是last立即发起新一轮的location 匹配,而break不会。
例子如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| location / { rewrite ^/test1 /test2; rewrite ^/test2 /test3 last; rewrite ^/test3 /test4; proxy_pass http://www.baidu.com; }
location = /test2 { return 200 "/test2"; }
location = /test3 { return 200 "/test3"; } location = /test4 { return 200 "/test4"; }
|
发送请求和结果如下:
1 2
| curl 127.0.0.1:8080/test1 /test3
|
这个结果符合我们的预期,发送了一个新的请求。
当如果将上面的location / 改成如下代码
1 2 3 4 5 6 7 8 9 10
| location / { rewrite ^/test1 /test2; rewrite ^/test2 /more/index.html break; rewrite /more/index\.html /test4;
proxy_pass https://www.baidu.com; }
|
浏览器输入127.0.0.1:8080/test1,代理到百度产品大全页面https://www.baidu.com/more/index.html;也就是请求地址重写。但是不会重新发送新一轮的请求。类如上面如果美欧proxy_pass指令,使用同样的请求将返回404。
但是,如果这些指令放在location为/download/下,最后一个标志应该替换为break,否则nginx将进行10次循环并返回500个错误:
1 2 3 4 5
| location /download/ { rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 break; rewrite ^(/download/.*)/audio/(.*)\..*$ $1/mp3/$2.ra break; return 403; }
|
rewrite 后的请求参数
如果替换字符串replacement包含新的请求参数,则在它们之后附加先前的请求参数。如果你不想要之前的参数,则在替换字符串 replacement 的末尾放置一个问号,避免附加它们。
1 2
| rewrite ^/users/(.*)$ /show?user=$1? last;
|
rewrite_log
1 2 3
| Syntax: rewrite_log on | off; Default: rewrite_log off; Context: http, server, location, if
|
开启或者关闭 rewrite模块指令执行的日志,如果开启,则重写将记录下notice 等级的日志到nginx 的 error_log中,默认为关闭 off
set
1 2 3
| Syntax: set $variable value; Default: — Context: server, location, if
|
设置指定变量的值。变量的值可以包含文本,变量或者是它们的组合形式。
1 2 3 4 5 6
| location / { set $var1 "host is "; set $var2 $host; set $var3 " uri is $request_uri"; return 200 "response ok $var1$var2$var3"; }
|
uninitialized_variable_warn
1 2 3
| Syntax: uninitialized_variable_warn on | off; Default: uninitialized_variable_warn on; Context: http, server, location, if
|
控制是否记录有关未初始化变量的警告。默认开启
参考
- 搞懂nginx的rewrite模块
- Module ngx_http_rewrite_module