Nginx的location的规则深入学习和记录

Nginx的location的规则深入学习和记录

  之所以写这篇博客,是因为之前配置Nginx的location遇到了各种问题,不甚其解,实在是感觉越配置越乱,开始以为自己会了,后来才发觉自己的认知其实是错误的。这篇并非什么解读源码之类的分析(还没到那水平),主要是对于我遇到的问题进行一些测试进行的总结,可能无法涵盖所有的情况,不恰当的地方还望指正。

表达式类型

  • = :进行普通字符精确匹配。也就是完全匹配。

  • ~ :表示执行一个正则匹配,区分大小写

  • ~* :表示执行一个正则匹配,不区分大小写

  • ^~:表示普通字符匹配,使用前缀匹配;如果匹配成功,则不再匹配其他location。

  • @ :它定义一个命名的 location,使用在内部定向时。

优先级说明

  nginx的location顺序没有太大关系,与表达式的类型有关。基本的规则是:相同类型的表达式,字符串长的会优先匹配。

按优先级排列说明:

  1. 等号类型(=)的优先级最高;一旦匹配成功不会再去查找其他匹配项。
  2. ^~类型表达式,特别注意这种知识普通字符匹配,并非正则匹配,而且如果它一旦匹配成功,则不再查找其他匹配项,即使后面匹配的字符串更长。
  3. 正则表达式类型(~ 或者~*)的优先级次之。如果有多个location的正则能匹配的话,则使用正则表达式最长的那个location。
  4. 常规字符串匹配类型,最低的优先级,匹配的规则:按前缀匹配。

测试的示例

  基本的测试环境,访问的测试地址:http://127.0.0.1/docs/introduction.html,代理访问:http://127.0.0.1:8081/docs/introduction.html;Nginx监听80端口,上游服务器Tomcat的端口为8081

情况1,下列正则匹配的location,都是不合法的案例

  相同点都是proxy_pass后面的上游地址在ip和port后面带有uri,正则匹配的后面是不可以有uri的,只能是端口结尾,不过后面可以带正则匹配的变量:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
情况2,正则匹配的location,成功的案例

  proxy_pass后面的上游地址在ip和port后面没有uri,也就是正则的proxy_pass的上游服务器地址没有配置uri。那么匹配正则表达式的location后的整个uri会作为上游服务器的请求的uri。例如下列的情况,http://127.0.0.1/docs/introduction.html,docs能匹配上,所以整个uri:/docs/introduction.html都会拼接到proxy_pass的url的后面。

  特别注意proxy_pass最后面不能有/,因为以/结尾,则匹配的location部分会被截取掉然后截取后的uri拼接到proxy_pass/后面。因为location是正则表达式,导致location的前半部分可能错在多种情况,
  例如location ~ docs,如果允许正则的location的proxy_pass/,那么按照以/结尾的proxy_pass的规则,访问的时候:http://127.0.0.1/docs和http://127.0.0.1/testdocs等等url都可以匹配上http://127.0.0.1/这个地址,在同一个location中不能存在多个访问的url地址匹配了同一个上游服务器的地址,故此正则匹配的location,是不可以配置proxy_pass的上游服务器地址为/结尾的。
在这里插入图片描述
在这里插入图片描述
下列的正则也能匹配到
在这里插入图片描述在这里插入图片描述
如果非正则,如下列写法必然会出错:
在这里插入图片描述
情况3:常规字符串匹配,正常访问

a.正常访问
在这里插入图片描述
  可以正常访问,其实通过:http://127.0.0.1/docsintroduction.html,也可以访问的,但是可能部分其他资源,例如css和图片的加载会出现问题。因为浏览器保存的baseUrl会变成了http://127.0.0.1/举个例子:有个资源文件为index.css,那么在加载introduction.html时,会需要加载它,但是应为浏览器的baseUrl的问题,导致请求服务器时地址变为了:http://127.0.0.1/index.css,那么可以对应一下下列的配置,显然是没有匹配到/docs的,所以index.css会404,页面渲染出现问题。所以正常一般都是这样访问:http://127.0.0.1/docs/introduction.html,那么baseUrl会保持为:http://127.0.0.1/docs/,就没有问题了

b.正常访问
在这里插入图片描述
c.正常访问
在这里插入图片描述
d.正常访问(同时验证网上某篇文章所描述的第四种情况)

  网上的例子,https://blog.51cto.com/chenwenming/1203537,按第四种来说应该会访问到了http://127.0.0.1/docsintroduction.html,显然不是。这篇文章中的第四种情况是错的,因为以http://127.0.0.1/docs/introduction.html访问是完全没问题。
在这里插入图片描述
情况4:访问失败

  访问http://127.0.0.1/docs/introduction.html失败,如果要成功访问,则访问地址应该为:http://127.0.0.1/docsdocs/introduction.html因为/docsdocs/docs会匹配上,然后后面的docs/introduction.html则直接回拼接到http://127.0.0.1:8081/的后面。
在这里插入图片描述
情况5:访问失败

  访问http://127.0.0.1/docs/introduction.html失败,如果要成功访问,则访问地址应该为:http://127.0.0.1/docs/docs/introduction.html。原因与情况4一致。
在这里插入图片描述
   对于情况4情况5,共同点都是roxy_pass的上游服务器地址以”/”结束,所以对于情况4中,在浏览器中的输入方位地址为:http://127.0.0.1/docs 等于 http://127.0.0.1/ ,所以访问http://127.0.0.1/docs/introduction.html 则访问上游服务器地址为:http://127.0.0.1/introduction.html 所以访问失败。对于情况5也是同样的原因。proxy_pass的上游服务器地址以”/”结束,则请求的uri需要与locaiton中的匹配成功后,还需减去前面匹配的部分,将后面剩余的拼接到proxy_pass的上游服务器url的后面。

规律总结

  这些规律总结,主要是基于上面的测试,还有一些是自己实践中的总结。
1.正则匹配的locationproxy_pass的上有服务器的地址中不能以/结尾。
2.正则匹配的location的整个url是可以直接拼接到proxy_pass最后的
3.关于location中的字符串是否是以/结尾:

  • a.不以/结尾,例如:location /docs
  • b.以/结尾,例如:location /docs/

  两者本质没什么区别,都是普通的常规字符串匹配类型,以/docstest和/docs/test为例,/docstestlocation /docs可以匹配,location /docs/无法匹配,而/docs/test则两者都可以匹配。

4.关于proxy_pass的上游服务器是否以/结尾

  • a.对于不是以/结尾的proxy_pass,例如:proxy_pass http://127.0.0.1:8081/docs
  • b.对于以/结尾的proxy_pass,例如:proxy_pass http://127.0.0.1:8081/docs/

  区别是不带/结尾的,则拼接在http://127.0.0.1:8081/docs后面存在两种可能,一种可能是/xxx,另一种是xxx,没有/;而对于以/结尾,则表示拼接在 http://127.0.0.1:8081/docs/后面只可能是xxx,即使请求的url与location匹配完后的后半部分是/xxx,则也只会取xxx,因为 http://127.0.0.1:8081/docs/后已经有/

#不以/结尾
location /docs {
   proxy_pass http://127.0.0.1:8081/docs;
}
#以/结尾
location /docs {
   proxy_pass http://127.0.0.1:8081/docs/;
}
请求的URL(浏览器)不以/结尾(Nginx转发)以/结尾(Nginx转发)
http://127.0.0.1/docs/introduction.htmlhttp://127.0.0.1:8081/docs/introduction.htmlhttp://127.0.0.1:8081/docs/introduction.html 【1】
http://127.0.0.1/docsintroduction.htmlhttp://127.0.0.1:8081/docsintroduction.html 【2】http://127.0.0.1:8081/docs/introduction.html [3]

针对表格中标注的地方补充说明:

【1】:对于该请求,按照规则,访问http://127.0.0.1/docs/introduction.html,在与/docs匹配后,剩下的后半部分为/introduction.html,如果直接拼接到已经带/结尾的proxy_pass,显然是要有问题,而以/结尾的proxy_pass,对这种的剩下的后半部分/introduction.html处理是不需要带/,而是将introduction.html拼接在最后,向上游发起请求。
【2】:404错误,原因是转发给上游服务器成了http://127.0.0.1:8081/docsintroduction.html
【3】:能拿到这个页面数据,但是其他资源拿不到,因为这个baseUrl是http://127.0.0.1/了,不再是http://127.0.0.1/docs,举个例子,此时页面获取的index.css,会以http://127.0.0.1/index.css发起,显然没法找到能匹配的nginx的location,所以其他资源都是404,其实也算是不正常的,这里用这两个为了能解释带/和不带的区别。

5.整个location只有个/
  这种其实没啥好解释的…,直接可以把它理解为一个默认拦截,任何未被拦截的请求(异常除外),都交给它处理。

location / {
   proxy_pass http://127.0.0.1:8081/docs;
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值