Nginx的rewrite模块详解
rewrite模块即ngx_http_rewrite_module模块,主要功能是改写请求URI,是Nginx默认安装的模块。rewrite模块会根据PCRE正则匹配重写URI,然后发起内部跳转再匹配location,或者直接做30x重定向返回客户端。
指令执行顺序
首先顺序执行server块中的rewrite模块指令,得到rewrite后的请求URI
然后循环执行如下指令
如果没有遇到中断循环标志,此循环最多执行10次,但是我们可以使用break指令来中断rewrite后的新一轮的循环
(1).依据rewrite后的请求URI,匹配定义的location块
(2).顺序执行匹配到的location中的rewrite模块指令
指令
break
Context:server,location,if
停止执行ngx_http_rewrite_module的指令集,但是其他模块指令是不受影响的
例子说明
server{ listen8080; #此处break会停止执行server块的return指令(return指令属于rewrite模块) #如果把它注释掉则所有请求进来都返回ok break; return200"ok"; location=/testbreak{ break; return200$request_uri; proxy_passhttp://127.0.0.1:8080/other; } location/{ return200$request_uri; } } #发送请求如下 #curl127.0.0.1:8080/testbreak #/other #可以看到返回`/other`而不是`/testbreak`,说明`proxy_pass`指令还是被执行了 #也就是说其他模块的指令是不会被break中断执行的 #(proxy_pass是ngx_http_proxy_module的指令) if Context:server,location
依据指定的条件决定是否执行if块语句中的内容
if中的几种判断条件
1.一个变量名,如果变量$variable的值为空字符串或者字符串"0",则为false
2.变量与一个字符串的比较相等为(=)不相等为(!=)注意此处不要把相等当做赋值语句啊
3.变量与一个正则表达式的模式匹配操作符可以是(~区分大小写的正则匹配,~不区分大小写的正则匹配,!!,前面两者的非)
4.检测文件是否存在使用-f(存在)和!-f(不存在)
5.检测路径是否存在使用-d(存在)和!-d(不存在)后面判断可以是字符串也可是变量
6.检测文件、路径、或者链接文件是否存在使用-e(存在)和!-e(不存在)后面判断可以是字符串也可是变量
7.检测文件是否为可执行文件使用-x(可执行)和!-x(不可执行)后面判断可以是字符串也可是变量
注意上面第1,2,3条被判断的必须是变量,4,5,6,7则可以是变量也可是字符串,-f/-d/-e/-x基本用法和bash是一致的.
set$variable"0"; if($variable){ #不会执行,因为"0"为false break; } #使用变量与正则表达式匹配没有问题 if($http_host~"^star\.igrow\.cn$"){ break; } #字符串与正则表达式匹配报错 if("star"~"^star\.igrow\.cn$"){ break; } #检查文件类的字符串与变量均可 if(!-f"/data.log"){ break; } if(!-f$filename){ break; }
return
Context:server,location,if
returncode[text]; returncodeURL; returnURL;
停止处理并将指定的code码返回给客户端。非标准code码444关闭连接而不发送响应报头。
从0.8.42版本开始,return语句可以指定重定向url(状态码可以为如下几种301,302,303,307),
也可以为其他状态码指定响应的文本内容,并且重定向的url和响应的文本可以包含变量。
有一种特殊情况,就是重定向的url可以指定为此服务器本地的urI,这样的话,nginx会依据请求的协议$scheme,server_name_in_redirect和port_in_redirect自动生成完整的url(此处要说明的是server_name_in_redirect和port_in_redirect指令是表示是否将server块中的server_name和listen的端口作为redirect用)
#returncode[text];返回ok给客户端 location=/ok{ return200"ok"; } #returncodeURL;临时重定向到百度 location=/redirect{ return302http://www.baidu.com; } #returnURL;和上面一样默认也是临时重定向 location=/redirect{ returnhttp://www.baidu.com; }
rewrite
Context:server,location,if
rewriteregexreplacement[flag];
rewrite指令是使用指定的正则表达式regex来匹配请求的urI,如果匹配成功,则使用replacement更改URI。rewrite指令按照它们在配置文件中出现的顺序执行。可以使用flag标志来终止指令的进一步处理。如果替换字符串replacement以http://,https://或$scheme开头,则停止处理后续内容,并直接重定向返回给客户端。
第一种情况重写的字符串带http://
location/{ #当匹配正则表达式/test1/(.*)时请求将被临时重定向到http://www.$1.com #相当于flag写为redirect rewrite/test1/(.*)http://www.$1.com; return200"ok"; } #在浏览器中输入127.0.0.1:8080/test1/baidu #则临时重定向到www.baidu.com #后面的return指令将没有机会执行了
第二种情况重写的字符串不带http://
location/{ rewrite/test1/(.*)www.$1.com; return200"ok"; } #发送请求如下 #curl127.0.0.1:8080/test1/baidu #ok #此处没有带http://所以只是简单的重写。请求的uri由/test1/baidu重写为www.baidu.com #因为会顺序执行rewrite指令所以下一步执行return指令响应了ok
rewrite的四个flag
1.last
停止处理当前的ngx_http_rewrite_module的指令集,并开始搜索与更改后的URI相匹配的location;(因为last英文含义是"继续",会继续尝试匹配跳转其他location)
2.break
停止处理当前的ngx_http_rewrite_module指令集,就像上面说的break指令一样;(break是"中断停止")
3.redirect
返回302临时重定向。(可以理解是"临时租房")
4.permanent
返回301永久重定向。(可以理解是"搬新家")
#没有rewrite后面没有任何flag时就顺序执行 #当location中没有rewrite模块指令可被执行时就重写发起新一轮location匹配 location/{ #不加flag,默认顺序执行 rewrite^/test1/test2; rewrite^/test2/test3;#此处发起新一轮location匹配uri为/test3 } location=/test2{ return200"/test2"; } location=/test3{ return200"/test3"; } #发送如下请求 #curl127.0.0.1:8080/test1 #/test3
last与break的区别
last和break一样它们都会终止此location中其他它rewrite模块指令的执行,
但是last立即发起新一轮的location匹配而break则不会
location/{ rewrite^/test1/test2; rewrite^/test2/test3last;#此处发起新一轮location匹配uri为/test3 rewrite^/test3/test4; proxy_passhttp://www.baidu.com; } location=/test2{ return200"/test2"; } location=/test3{ return200"/test3"; } location=/test4{ return200"/test4"; } #发送如下请求 #curl127.0.0.1:8080/test1 #/test3 当如果将上面的location/改成如下代码 location/{ rewrite^/test1/test2; #此处不会发起新一轮location匹配;当是会终止执行后续rewrite模块指令重写后的uri为/more/index.html rewrite^/test2/more/index.htmlbreak; rewrite/more/index\.html/test4;#这条指令会被忽略 #因为proxy_pass不是rewrite模块的指令所以它不会被break终止 proxy_passhttps://www.baidu.com; } #发送如下请求 #浏览器输入127.0.0.1:8080/test1 #代理到百度产品大全页面https://www.baidu.com/more/index.html;
rewrite后的请求参数
如果替换字符串replacement包含新的请求参数,则在它们之后附加先前的请求参数。如果你不想要之前的参数,则在替换字符串replacement的末尾放置一个问号,避免附加它们。
#由于最后加了个?,原来的请求参数将不会被追加到rewrite之后的url后面 rewrite^/users/(.*)$/show?user=$1?last;
rewrite_log
Context:http,server,location,if
开启或者关闭rewrite模块指令执行的日志,如果开启,则重写将记录下notice等级的日志到nginx的error_log中,默认为关闭off
Syntax:rewrite_logon|off;
set
Context:server,location,if
设置指定变量的值。变量的值可以包含文本,变量或者是它们的组合形式。
location/{ set$var1"hostis"; set$var2$host; set$var3"uriis$request_uri"; return200"responseok$var1$var2$var3"; } #发送如下请求 #curl127.0.0.1:8080/test #responseokhostis127.0.0.1uriis/test
uninitialized_variable_warn
Context:http,server,location,if
控制是否记录有关未初始化变量的警告。默认开启
内部实现
该ngx_http_rewrite_module模块指令是在配置阶段编译成被请求处理过程中解释内部指示。解释器是一个简单的虚拟堆栈机。
例如,指令
location/download/{if(forbidden)return403;if(forbidden){return403;}if(forbidden)return403;if(slow){limit_rate10k;}rewrite^/(download/.)/media/(.)…*$/$1/mp3/$2.mp3break;}
将被翻译成以下说明:
variable$forbiddencheckagainstzeroreturn403endofcodevariable$slowcheckagainstzeromatchofregularexpressioncopy“/”copy$1copy“/mp3/”copy$2copy“.mp3”endofregularexpressionendofcode
请注意,上面的limit_rate指令没有任何指令,因为它与ngx_http_rewrite_module模块无关。为if块创建一个单独的配置。如果条件成立,则将为此配置分配一个请求,该请求limit_rate等于10k。\
指令
rewrite^/(download/.)/media/(.)…*$/$1/mp3/$2.mp3break;
如果正则表达式中的第一个斜杠放在括号内,则可以简化:
rewrite^(/download/.)/media/(.)…*$$1/mp3/$2.mp3break;
相应的指令将如下所示:
matchofregularexpressioncopy$1copy“/mp3/”copy$2copy“.mp3”endofregularexpressionendofcode
location(非rewrite模块)
语法
在server块中使用,如:
- server{
- location表达式{
- }
location表达式类型
如果直接写一个路径,则匹配该路径下的表示执行一个正则匹配,区分大小写
~*表示执行一个正则匹配,不区分大小写
^~表示普通字符匹配。使用前缀匹配。如果匹配成功,则不再匹配其他location。
=进行普通字符精确匹配。也就是完全匹配。
优先级
1.等号类型(=)的优先级最高。一旦匹配成功,则不再查找其他匹配项。
2.^~类型表达式。一旦匹配成功,则不再查找其他匹配项。
3.正则表达式类型(~~*)的优先级次之。如果有多个location的正则能匹配的话,则使用正则表达式最长的那个。
4.常规字符串匹配类型。按前缀匹配。
到此这篇关于Nginx的rewrite模块详解的文章就介绍到这了,更多相关Nginx的rewrite内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。