前两篇博客简单总结了一下nginx的相关配置和nginx的location,但是有些混乱,这篇博客在梳理前面的基础上,同时总结一下rewrite
在之前博客的基础上,再梳理一下nginx匹配的流程和步骤,网上有些大牛对这个步骤做了详细总结,其中有一篇比较清晰的图解,觉得不错,就照着画了一份。
nginx根据一个完整的url中的域名和端口,确定最终会选择配置中的哪一个server。
这是关键的一步,nginx根据请求的url进行前缀匹配,匹配方式在上一篇博客中已经有相关流程图进行介绍,这里不再赘述。nginx根据前缀进行匹配命中之后,将原有的url上分为匹配中的url和未匹配中的url,在上图中分别对应path1匹配部分,path2匹配部分,然后组装相关文件查找或者代理转发的路径。这里需要一个实例进行说明
在nginx的配置文件中有如下location的配置
location /pages{
root ngtest;
}
一个很简单的配置,无需多做解释
如果有以下url——www.testng.com:8089/pages/a.html
则nginx会进行如下处理,根据请求过来的url进行前缀匹配,前缀为/pages开头,最终会匹配中上述location配置(这里都是最简单的匹配情况,没有加入上一篇博客中较为复杂的匹配规则)这个时候的url会被拆成匹配中的path1=/pages
和未匹配中path2=a.html
这一步名字叫代理转发,与其不如叫组装对应的资源文件路径,这里就需要详细介绍root,alias和proxy_pass配置的一些细节了,还有一个rewrite,后面再详细介绍。
root是代理转发中最为简单的一个配置,root指明了查找文件的根目录,最终需要查找的文件路径为——root+path1/path2
以上述实例为例,root=ngtest这里没有指定绝对路径,默认相对于当前nginx的安装路径而言,因此最终读取的文件路径为:当前nginx的安装路径下的ngtest/pages/a.html
文件
如果上述的location配置改成如下所示
location /pages{
alias target;
}
配置成alias,则有些不同,alias的意思是别名,别名意味着替换,这里会将url中匹配中的path1替换成alias所指定的值,例如如果请求依旧是www.testng.com:8089/pages/a.html,在匹配中该location配置的情况下,最终的path1会被替换成target,最终nginx回去读取当前安装路径下的/target/a.html文件,如果在target文件夹下没有a.html文件,则会出现404界面。
换句话说,alias与root的区别就在于,root将path1+path2传递给下一个模块,而alias只将path2传递给下一个模块。
除了root和alias,还有proxy_pass,利用这个配置,可以将请求转发给其他第三方服务器。关于这个配置,有个细节需要总结
例如:nginx.conf中有如下proxy_pass的配置
location /nglearn{
proxy_pass http://192.168.0.112:8080; ###这里没有收尾的/
}
location /proxy{
proxy_pass http://192.168.0.110:8080/;###这里有收尾的/
}
为了测试这个实例,在相关服务器上安装了tomcat(这个服务器与nginx不是同一个机器),并启动了一个简单的web应用。
发送一个如下请求——http://www.testng.com:8089/nglearn/index.html,最终会命中/nglearn的location的配置,这个时候得到的path1与path2分别为:path1=nglearn,path2=/index.html,由于proxy_pass的配置并没有以/
结尾,因此,最终的转发路径为proxy_pass+path1+path2
即http://192.168.0.112:8080/nglearn/index.html
发送一个如下请求——http://www.testng.com:8089/proxy/nglearn/index.html,最终会命中/proxy的location配置,这个时候得到的path1与path2分别为:path1=proxy,path2=/nglearn/index.html,由于proxy_pass的配置以/
结尾因此,最终的转发路径为proxy_pass+path2
即http://192.168.0.110:8080/nglearn/index.html
ps:192.168.0.112与192.168.0.110是我自己虚拟出来的两台虚拟机的IP地址。
这个就比较简单,根据第三步生成的url,找到指定的文件然后返回给客户端。
nginx官网中关于rewrite的介绍貌似不太多——nginx官网关于rewrite的介绍。
rewrite的语法格式如下
rewrite regex replacement [flag];
简单实例:
location /b.html{
rewrite ^/ /rewrite.html redirect;
}
ps:下面一段来自官网翻译
如果请求的uri匹配rewrite中的正则表达式,则请求的uri部分会被替换为指定的replacement部分的字符串。rewrite指令会按照在配置文件中出现的顺序进行执行(毕竟rewrite可以在server块和location块中存在)。后面的flag部分决定rewrite进一步的执行是否停止。如果replacement部分以"http://",“https://”,"$scheme"开头,则rewrite流程终止,重定向返回客户端。
这一段话将rewrite各个部分的作用都做了阐述,大致可以理解为以下几个部分
部分 | 作用 |
---|---|
regex | 正则,如果与之匹配则对uri进行replacement的替换 |
replacement | uri需要替换的值 |
flag | 有几种取值,官网中也有介绍,决定了rewrite指令进一步的执行方向 |
关于flag官网也有详细的说明
flag可以有如下几个值
flag取值 | 作用 |
---|---|
last | 停止继续执行rewrite指令,以replacement的值开始新的location匹配 |
break | 停止继续执行rewrite的指令,直接返回客户端 |
redirect | 返回客户端302临时重定向状态码,客户端会重新发起replacement值的请求 |
permanent | 返回客户端301的永久重定向操作,客户端会重新发起replacement值的请求 |
空 | 如果不指定flag值,则会执行顺序执行语句块中的rewrite,以最后一个rewrite结果为准,同时如果最后一个rewrite还是没有指定flag,则最后一个rewrite依旧会引发replacement的location重匹配 |
回到上面的实例,上面指定了redirect的flag为redirect,且location的匹配值为/b.html,如果在浏览器中输入请求/b.html的uri,则其实会被nginx服务器rewrite到去获取服务端的rewrite.html这个文件,而不是原本的b.html文件,同时flag是redirect,这个不是服务端重定向,而是客户端重定向,我们在浏览器中输入的uri也会发生响应的变化。如下动图所示:
关于last的用法,官网中有一些嘱咐,为了说明last的一些问题,这里先用一个实例看一下last的真正作用。如下实例需要引入nginx的echo模块,关于这个模块的安装和添加,可以参考这篇大牛的博客,这里不展开叙述——nginx 安装echo模块。也没什么东西主要利用add-module指令给nginx添加相关模块即可。
如果flag设置为last,请看如下location的配置实例
location /d.html{
rewrite ^/ /rewrite.html last;
}
location /rewrite.html{
echo "final rewrite request";
}
针对d.html的uri,匹配相关的rewrite规则,replacement字符串为rewrite.html,flag设置为last。最终会rewrite到我们配置的rewrite.html么?可能并不是,具体执行结果参考如下动图:
可以看到,并不是和上一个实例一样输出的rewrite.html的内容,而是输出了location中/rewrite.html配置的echo的内容。到这里,应该能看出last的作用——停止当前的rewrite的执行,拿着rewrite中指定的新的uri,重新发起一次location的匹配,以最新的结果为准。
如果我们配置如下的location
location /d.html{
rewrite ^/ /rewrite.html last;
}
location /rewrite.html{
rewrite ^/ /d.html last;
}
如果这样配置,就会出现死循环,nginx会返回500异常给客户端。官网中针对这个问题也给出了一个实例,这里不再赘述,只是实际使用中建议不轻易使用last标签如果使用last标签,需要避免死循环。
关于flag为空的情况,再以实例为基础多说两句:
location /a.html{
rewrite ^/ /rewrite.html;
rewrite ^/ /empty.html;
echo "request a.html";
}
location /empty.html{
alias d.html;
echo "request empty.html";
}
如果有上述的location配置,针对a.html的uri,则在请求的时候,会最终匹配/empty.html的rewrite,然后rewrite最终会重新匹配location,最终输出"request empty.html"给客户端。
可以参考如下动图
在简单总结了nginx的location匹配的基础上,总结了一下rewrite的用法,location和rewrite是nginx中最为重要的内容之一,后续会继续总结nginx的用法。