Nginx-location匹配规则

107次阅读

共计 1409 个字符,预计需要花费 4 分钟才能阅读完成。

以下列配置为例

server {
    listen       80;
    server_name  jouypub.com;

    location ^~ /. {return 404;}
    location ^~ /api {proxy_pass http://localhost:8000;}
    location / {root /services/apps/front/;}
}

location 语法规则:location [=|~|~*|^~] /uri/ {…}

= 开头表示精确匹配
^~ 开头表示 uri 以某个常规字符串开头,理解为匹配 url 路径即可
~ 表示区分大小写的正则匹配
~* 表示不区分大小写的正则匹配
!~!~* 分别为区分大小写不匹配及不区分大小写不匹配 的正则
/ 通用匹配,任何请求都会匹配到。

如果匹配规则以 ^ 开头,就是匹配以指定字符串开头的路径,如果没有就是匹配 url 中的内容是否包含指定字符串
如果匹配规则以 $ 结尾,就是匹配以指定字符串结尾的路径

多个 location 配置的情况下匹配顺序为(当有匹配成功时候,停止匹配,按当前匹配规则处理请求):

  1. 优先匹配 =
  2. 其次匹配 ^~
  3. 按照文件中的匹配顺序执行
  4. 最后匹配 /

举例

1、必选规则

location / {root /services/apps/front/;}

2、匹配静态资源

location ^~ /static/ {root /services/apps/front/static;}
location ~* \.(gif|jpg|jpeg|png|css|js|ico)$ {root /webroot/res/;}

3、防盗链

location ~* \.(gif|jpg|swf)$ {
    valid_referers none blocked jouypub.com files.jouypub.com;
    if ($invalid_referer) {rewrite ^/ http://$host/logo.png;}
}

jouypub.com、files.jouypub.com 是运行出现的白名单

4、根据文件类型设置过期时间

location ~* \.(js|css|jpg|jpeg|gif|png|swf)$ {if (-f $request_filename) {
        expires 1h;
        break;
    }
}

5、禁止访问某个目录

location ~* \.(txt|doc)${
    root /services/apps/front/doc;
    deny all;
}

location 中的 / 结尾和非 / 结尾

location ^~ /api {proxy_pass http://localhost:8000;}
location ^~ /api {proxy_pass http://localhost:8000/;}

访问路径 http://www.jouypub.com/api/a.html
规则 1 会被转发到:http://localhost:8000/api/a.html
规则 2 会被转发到:http://localhost:8000/a.html


欢迎订阅「K 叔区块链」– 专注于区块链技术学习

博客地址:http://www.jouypub.com
简书主页:https://www.jianshu.com/u/756c9c8ae984
segmentfault 主页:https://segmentfault.com/blog/jouypub
腾讯云主页:https://cloud.tencent.com/developer/column/72548

正文完
 0

Nginx-Location匹配规则

108次阅读

共计 3231 个字符,预计需要花费 9 分钟才能阅读完成。

本文非完全原创, 更多的是将相关资料进行整理

Last-Modified: 2019 年 5 月 10 日 15:28:29

参考链接

  • linux Nginx 配置篇:location 的匹配规则(附测试验证过程)

规则语法

语法 匹配规则
普通匹配(遵循最大前缀匹配规则, 优先度比正则低)
= 精确 (严格) 匹配, 优先度最高
后续不再匹配正则
^~ 非正则匹配 ( 依然遵循 最大前缀匹配规则)
后续不再匹配正则
~ 表示区分大小写的正则匹配
~* 表示不区分大小写的正则匹配
/ 通用匹配,任何请求都会匹配到 (本质上等同于语法 )

!~!~* 分别为区分大小写不匹配及不区分大小写不匹配 的正则, 但是是用于条件判断的时候(即 if 语句)

if ($host !~* "^www\.") {# ...}

匹配简单来说:

  1. 优先 匹配 = 精确匹配, 若未匹配到则转下一步骤
  2. 依照 最大前缀匹配 规则, 先匹配 普通规则 ( , ^~)

    若最终匹配到 ^~, 则使用

    若匹配到 或 未匹配到, 则转下一步骤(当前匹配结果暂时保存)

  3. 按照物理存储顺序, 若匹配到 任意一条正则, 马上使用(无视后面正则)

    若未匹配到任意正则, 则使用步骤 2 中匹配到 普通正则

location 分类

只有两类:正则 location 和普通 location

~~* 为正则 location
=^~@和无任何前缀的都属于普通 location,另外,@是用作服务端内部的一种转发行为,很少用,在此不做讨论。

匹配顺序:

  1. 先普通,再正则
  2. 普通 location 之间的匹配顺序:按最大前缀匹配
    location /a/{}location /a/b/ {}, 请求 http://a/b/c.html 匹配的是 location /a/b/ {}
  3. 正则 location 之间的匹配顺序:按配置文件中的物理顺序匹配,只要匹配到一条正则,就不再考虑后面的
  4. 若普通 location 匹配到 精确匹配= 或 非正则匹配 ^~, 则不再进行后续的正则匹配
  5. 普通 location 与正则 location 之间的匹配结果选择

    1. 普通 location 先匹配,匹配到了结果,只是一个临时结果;
    2. 会继续正则 location 的匹配,

      1. 如果匹配到正则,则用匹配到的正则结果;
      2. 如果没有匹配到正则,则继续用普通匹配的那个结果

综上,常规的顺序是匹配完普通 location,还要继续匹配正则 location,但是,也可以告诉 nginx,匹配到了普通 location,就不要再搜索匹配正则 location 了,通过在普通 location 前面加上 ^~ 符号,^表示非,~表示正则,^~就是表示不要继续匹配正则。

除了 ^~= 也可阻止 nginx 继续匹配正则,区别在于 ^~ 依然遵循最大前缀匹配规则,而 = 是严格匹配

扩展

location / {}location =/ {}的区别

/ {}作为普通匹配,是遵循最大前缀匹配原则的,所以,对于一个 url,如果有更特殊合适的匹配,就选特殊合适的,如果没有更特殊合适的匹配,也有 / {}兜着,就像是默认配置一样

=/ {} 遵循的是严格匹配规则,只能匹配到 http://ip:port/,同时会停止搜索正则匹配。

测试

接下来测试验证。

1. 先验证第二条:普通 location 之间的匹配顺序:按最大前缀匹配

nginx.conf 配置:

# 普通 location
location  /a/b {return 666;}
#普通 location
location /a/b/c {return 777;}

测试链接:http://192.168.88.38/a/b,http 状态码为 666,符合预期。如图(后面的测试可自行 F12 打开浏览器控制台查看 http 状态码,不再截图):

测试链接:http://192.168.88.38/a/b/c,http 状态码为 777,匹配的是 location /a/b/c {return 777;},符合预期。

2. 验证第三条:正则 location 之间的匹配顺序:按配置文件中的物理顺序匹配,只要匹配到一条正则,就不再考虑后面的

nginx.conf 配置:

location ~* /a {return 999;}
#匹配 a - z 的任意一个字母
location ~* ^/[a-z]$ {return 666;}

测试链接:http://192.168.88.38/a,http 状态码 999,匹配的是 location ~* /a {renturn 999;},符合预期。
将 nginx.conf 中的两个正则匹配顺序调换下:

location ~* ^/[a-z]$ {return 666;}

location ~* /a {return 999;}

测试链接:http://192.168.88.38/a,http 状态码 666,匹配的是 location ~* ^/[a-z]$,符合预期。

3. 验证第 4 条,其实第 4 条就相当于是总结性的匹配顺序了:

nginx.conf 配置:

# 普通 location
location /a {return 666;}
 #普通 location
location  /a/b {return 777;}
#正则 location 
location ~* /a/b {return 888;}

测试链接:http://192.168.88.38/a,http 状态码 666,匹配到普通 location,location /a {return 666;}, 符合预期。
测试链接:http://192.168.88.38/a/b,http 状态码 777,先进行普通 location 匹配,遵循最大前缀原则,匹配到 location /a/b {return 777;},但是,这只是一个临时结果,因为接下来还要继续往下进行正则 location 匹配,匹配到 location ~* /a/b {return 888;},最终返回结果为 888。符合预期。
将正则 location 的规则改下:

# 普通 location
location /a {return 666;}
#普通 location
location  /a/b {return 777;}
#正则 location
location ~* /a/c {return 888;}

测试链接:http://192.168.88.38/a/b,http 状态码 777,匹配到 location /a/b {return 777;},并且因为接下来没有符合的正则 location,所以最终返回为 777,符合预期。

综上,location 的匹配顺序及结果取值都符合 2,3,4 点结论。
接下来再测试验证普通 location 中的 ^~ 及 = 符号对于匹配搜索过程的阻断效果,当然,别忘了这俩符号的真实作用。^~ 为普通字符匹配,= 为精确匹配。
^~ 测试验证 nginx.conf 配置:

location /a {return 666;}
#普通匹配
location ^~ /a/b {return 777;}
#正则 location
location ~* /a/b {return 888;}

测试链接:http://192.168.88.38/a/b,匹配到 location ^~ /a/b {return 777;}后,因为使用了 ^~ 符号,不再继续搜索正则 location 匹配,所以,虽然下面有符合条件的正则 location,但是最终还是返回了 777,符合预期。
= 测试验证 nginx.conf 配置:

location /a {return 666;}
#普通匹配
location = /a/b {return 777;}
#正则 location
location ~* /a/b {return 888;}

测试链接:http://192.168.88.38/a/b,匹配到 location = /a/b {return 777;}后,因为使用了 = 符号,不再继续搜索正则 location 匹配,最终返回 777,符合预期。

另附上常用正则表达式:

  • .:匹配除换行符外的任意字符
  • ?:重复 0 次或 1 次
  • :重复 1 次或更多次
  • :重复 0 次或更多次
  • d:匹配数字
  • ^:匹配字符串的开始
  • $:匹配字符串的结束
  • {n}:重复 n 次
  • {n,}:重复 n 次或更多次
  • :匹配单个字符,如此处的字符 c
  • [a-z]:匹配 a - z 小写字母的任意一个
  • (a|b|c):匹配 a 或 b 或 c </span>

正文完
 0