rewrite模块即ngx_http_rewrite_module
模块,主要功能是改写请求URI,是Nginx默认安装的模块。rewrite模块会根据PCRE正则匹配重写URI,而后发起内部跳转再匹配location,或者直接作30x重定向返回客户端。nginx
rewrite模块的指令有break, if, return, rewrite, set等。rewrite指令所执行的顺序以下:正则表达式
基本语法: rewrite regex replacement [flag];
上下文:server, location, if浏览器
regex是PCRE 风格的,若是regex匹配URI,那么URI就会被替换成replacement,replacement 就是新的URI。若是rewrite同一个上下文中有多个这样的正则,匹配会依照rewrite指令出现的顺序前后依次进行下去,匹配到一个以后并不会终止,而是继续往下匹配,直到返回最后一个匹配上的为止。若是想要停止继续往下匹配,可使用第三个参数flag。cookie
若是新URI字符中有关于协议的任何东西,好比http://或者https://等,进一步的处理就终止了,直接返回客户端302。curl
若是返回的是30x,那么浏览器根据这个状态码和Location响应头再发起一次请求,而后才能获得想要的响应结果。可是,若是不是返回30x状态码,那么跳转就是内部的,浏览器不作跳转就能获得相应。url
注意:regex直接就是正则表达式,不要再前面添加~符号调试
flag 参数能够有如下的一些值:日志
若是有last参数,那么中止处理任何rewrite相关的指令,当即用替换后的新URI开始下一轮的location匹配code
中止处理任何rewrite的相关指令,就如同break 指令自己同样。server
last的break的相同点在于,当即中止执行全部当前上下文的rewrite模块指令;不一样点在于last参数接着用新的URI立刻搜寻新的location,而break不会搜寻新的location,直接用这个新的URI来处理请求,这样能避免重复rewite。所以,在server上下文中使用last,而在location上下文中使用break。
replacement 若是不包含协议,仍然是一个新的的URI,那么就用新的URI匹配的location去处理请求,不会返回30x跳转。可是redirect参数可让这种状况也返回30x(默认302)状态码,就像新的URI包含http://和https://等同样。这样的话,浏览器看到302,就会再发起一次请求,真正返回响应结果的就是这第二个请求。
和redirect参数同样,只不过直接返回301永久重定向
虽然说URI有了新的,可是要拼接成完整的URL还须要当前请求的scheme,以及由server_name_in_redirect
和port_in_redirect
指令决定的HOST和PORT.
还有一个比较有意思的应用,就是若是replacement中包含请求参数,那么默认状况下旧URI中的请求参数也会拼接在replacement后面做为新的URI,若是不想这么作,能够在replacement的最后面加上?。
举例说明:
rewrite ^/users/(.*)$ /show?user=$1? last;
这样的新URI仍是 /show?user=xxx
但若是不加问号:
rewrite ^/users/(.*)$ /show?user=$1 last;
获得的新URI就是/show?user=$1&xxx=xxx
。其中xxx=xxx是旧URI所带的请求参数。
在server中使用的状况:
server { ... rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 last; rewrite ^(/download/.*)/audio/(.*)\..*$ $1/mp3/$2.ra last; return 403; #没有匹配上,那就返回403咯 ... }
注意,在server中使用rewrite ,咱们使用的flag是last,可是在location中,咱们却只能用break:
location /download/ { rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 break; rewrite ^(/download/.*)/audio/(.*)\..*$ $1/mp3/$2.ra break; return 403; }
若是在location的rewrite也使用last,便会再次以新的URI从新发起内部重定向,再次进行location匹配,而新的URI中极有可能和旧的URI同样再次匹配到相同location中,这样死循环发生了。当循环到第10次时,Nginx会终止这样无心义的循环,并返回500错误。这点须要特别的注意。
基本语法:break;
上下文:server, location, if
中止处理任何rewrite的相关指令。若是出如今location里面,那么全部后面的rewrite模块指令都不会再执行,也不发起内部重定向,而是直接用新的URI进一步处理请求。
基本语法:if (condition) { ... }
上下文:server, location
根据条件condition的真假决定是否加载{...}中的配置,{...}中的配置能够继承外面的配置,也能够对外面已有配置指令进行覆写。
条件condition是针对变量而言的,变量既能够是系统变量,也能够是自定义的,能够是下面几种状况:
$var
自己时,当且仅当变量值为空字符或者0时,条件为false,其他状况皆为 true$var
经过"="或者"!="与字符串相比较,即$var = xxx
或者$var != xxx
-f
-d
-e
-x
等检验文件或者目录属性或者存在与否的运算符其中,对于 3. 匹配一个正则表达式的状况,能够细分为:
$var ~ Reg
表示大小写敏感匹配$var ~* Reg
表示大小写不敏感匹配$var !~ Reg
表示大小写敏感不匹配$var !~* Reg
表示大小写不敏感不匹配Reg 中能够捕获变量,当其中包含有 } 或者 ; 时须要用双引号或者单引号括起来。
另外,对于 4. 检验文件存在或者属性的状况,具体说来也分为如下几种:
if ($http_user_agent ~ MSIE) { rewrite ^(.*)$ /msie/$1 break; } location /xiao/ { if ($http_user_agent ~ Mozilla/5.0) { #若是是chrom浏览器 rewrite ^(.*)$ http://www.example.com; #返回客户端302 } if ($http_user_agent ~ curl) { # 若是是curl 发起请求 rewrite ^/xiao/(.*)$ /xiao/$1.txt break; #获得新的URI } } if ($http_cookie ~* "id=([^;]+)(?:;|$)") { set $id $1; #提取了变量$1 } if ($request_method = POST) { return 405; #能够限制Request Method } if ($slow) { limit_rate 10k; #这个配置会加在location里面 } if ($invalid_referer) { return 403; }
基本语法:return code [text];或者return code URL;或者return URL;
上下文:server, location, if
中止任何的进一步处理,而且将指定状态码返回给客户端。若是状态码为444(此状态码是非标准的),那么直接关闭此TCP链接。
return的参数有四种形式:
return code
此时,响应内容就是nginx所默认的,好比503 Service Temporarily Unavailable; 若是是444那就直接关闭TCP链接,也能够是其余值(644等),可是没啥意义return code text
由于要带响应内容,所以code不能是具备跳转功能的30xreturn code URL
此时URI能够为URI作内部跳转,也能够是具备“http://”或者“https://”等协议的绝对URL,直接返回客户端,而code是30x(301, 302, 303, 307,308)return URL
此时code默认为302,而URL必须是带“http://”等协议的绝对URL基本语法:set $variable value;
上下文:server, location, if
这是一个有用的指令,用来定义变量,变量的值能够包含字符串,另外的变量或者是两者结合。
set $var = $http_x_forwarded_for;
注意:在Nginx中,除非特殊说明,大部分地方字符串的不须要引号括住,字符串和变量的拼接也不须要引号
基本语法:rewrite_log on | off;
上下文:http, server, location, if
若是开启 on,那么当发生rewrite时,会产生一个notice级别的日志;不然不会产生任何日志。默认状况下是不产生的,但在调试的时候能够将其置为on。
以上这些指令,基本涵盖了rewrite模块的全部应用,在须要改写请求URI,或者作跳转时很是有用。