Nginx location 匹配规则详解

最近团队在做前后端分离,前端这边接手了 Nginx 和 node 层。说实话,跟 Nginx 打交道的次数一下子多了起来,尤其是 location 配置,几乎每次上线都要改一改。

location 匹配规则看似简单,实则有不少细节容易忽略。今天就把我总结的 location 匹配规则分享出来,希望能帮到有需要的小伙伴。

先说语法

location 的语法其实挺简单的:

1
2
location [ = | ~ | ~* | ^~ ] uri { ... }
location @name { ... }

一个 location 关键字,后面跟着可选的修饰符,然后是要匹配的路径,花括号里是要执行的配置。

修饰符有四种:

  • = - 精确匹配,请求路径必须和后面的字符串完全一样才能命中
  • ~ - 正则匹配,区分大小写
  • ~* - 正则匹配,不区分大小写
  • ^~ - 前缀匹配,如果这个是最佳匹配,就不再继续查找正则了

匹配过程才是重点

知道语法只是第一步,真正让人头疼的是:这么多 location 放在一起,到底谁先匹配?

匹配过程大致是这样的:

第一步:先找前缀字符定义的 location,记录下最长匹配的那条。

第二步:如果找到了精确匹配(就是用了 = 修饰符的),直接用它的配置,结束查找。

第三步:按顺序找正则定义的 location,找到第一个匹配的就停,用它的配置。

第四步:如果正则都没匹配上,就用第一步记录的最长前缀匹配。

这里有两条很重要的结论:

  1. 正则 location 的顺序很重要!因为找到第一个匹配的正则就停了,后面定义的正则写得再好也没机会了。

  2. 用精确匹配 = 可以提高查找速度。比如经常请求根路径 /,可以用 location = / 来定义。

举个栗子

光说规则太抽象了,来看个实际配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
location = / {
[ configuration A ]
}

location / {
[ configuration B ]
}

location /user/ {
[ configuration C ]
}

location ^~ /images/ {
[ configuration D ]
}

location ~* \.(gif|jpg|jpeg)$ {
[ configuration E ]
}

咱们逐个请求来分析:

  • 请求 /匹配 A。精确匹配,直接命中,没二话。

  • 请求 /index.html匹配 B。先找前缀匹配,最长是 B。然后找正则,没匹配上,所以用 B。

  • 请求 /user/index.html匹配 C。前缀最长匹配是 C,后面没匹配的正则,就用 C。

  • 请求 /user/1.jpg匹配 E。前缀最长匹配是 C,但正则 E 匹配上了,正则优先级更高,所以用 E。这个坑我踩过!

  • 请求 /images/1.jpg匹配 D。前缀最长匹配是 D,因为用了 ^~ 修饰符,所以跳过正则查找,直接用 D。如果没有 ^~,其实会匹配 E。

  • 请求 /documents/about.html匹配 B。只有 B 能匹配上。

@name 是干嘛的

@ 用来定义一个命名 location,主要用于内部重定向,不能处理正常请求。

1
2
3
4
5
6
location / {
try_files $uri $uri/ @custom
}
location @custom {
# ...do something
}

当访问的 url 找不到对应文件时,就会重定向到 @custom 这个命名 location。挺好用的,特别是做 fallback 逻辑的时候。

不过要注意,命名 location 里面不能再嵌套其他命名 location。

结尾斜杠的事儿

关于 URL 结尾的 /,有三点值得说:

  1. location 配置里有没有 / 其实没影响,/user//user 是一样的。

  2. 如果 URL 是 https://domain.com/ 这种形式,结尾有没有 / 都不会重定向。因为浏览器发请求时默认会加上。

  3. 如果 URL 是 https://domain.com/some-dir/,结尾如果少了 / 会触发重定向。因为按照约定,结尾有 / 表示目录,没有表示文件。服务器找不到 some-dir 文件时,会把它当成目录,重定向到 /some-dir/

小结

最后总结一下优先级,从高到低:

  1. = 精确匹配(最高优先级,立即停止)
  2. ^~ 前缀匹配(停止正则搜索)
  3. ~~* 正则匹配(按配置文件顺序)
  4. 普通前缀匹配(最长匹配原则,最低优先级)

搞清楚这些规则后,配置 Nginx location 就更加得心应手了。希望这篇总结对大家有所帮助。