Nginx location 匹配规则

2019-09-17

要写 nginx 配置文件,location 是一个比较重要的指令块,匹配到的 url 会执行对应 location 块中的语句,然而 location 匹配的类型有多种,经常会不记得不同类型的匹配规则,现在在此总结一下。

location 匹配类型

  1. 精确匹配 =
  2. 普通字符串匹配,无修饰符
  3. 优先字符串匹配 ^~
  4. 正则匹配 ~
  5. 不区分大小写的正则匹配 ~*

可以看到,大体分为两大类,一种是字符串类型(第1、2、3种类型),一种是正则类型(第4、5种类型),nginx 也是把两种类型分开处理的:先按顺序扫描字符串类型的 location 块,再按顺序扫描正则类型的 location 块,其中字符串类型都是区分大小写的。

对于多个同级的 location 块,只会执行其中一个块的代码,下面说明 nginx 的匹配过程,即如何确定执行哪一个块。

匹配过程

先按顺序扫描字符串类型的 location 块:

  1. 对于普通字符串匹配,会判断字符串是否匹配 url path 的开头,并且会记录所有成功匹配的普通字符串 location 中匹配长度最长的项,然后继续后续的匹配
  2. 对于 = 精确匹配,会判断字符串是否完全等于 url path,如果全等,则停止剩余 location 块的匹配,执行当前块
  3. 对于 ^~ 优先字符串匹配,跟普通字符串匹配的规则是一样的,即判断字符串是否匹配 url path 的开头,不同的是如果匹配成功,则立即停止剩余 location 块的匹配,执行当前块

如果匹配还未停止,则按顺序扫描正则类型的 location 块:

  1. 对于正则匹配 ~,如果匹配成功,则停止剩余 location 块的匹配,执行当前块
  2. ~*~ 的规则是一样的,只是正则不区分大小写

如果不存在能成功匹配的正则类型,则取之前记录的普通字符串匹配的匹配长度最长项的 location 块并执行。

按照这个匹配过程,能总结出不同匹配类型的优先级:

= 精确匹配 = ^~ 优先字符串匹配 > ~ 正则匹配 = ~* 不区分大小写的正则匹配 > 普通字符串匹配

某些类型的 location 块的顺序是有意义的,对于那些立即停止的 location 匹配类型,顺序在前的则会优先匹配到,匹配成功则不再进行后续 location 块的匹配。例如对于正则匹配来说,如果有多个正则都能匹配某个 url path,则取顺序在最前的那个执行。但是对于普通字符串匹配来说,顺序则是无意义的,因为只会匹配到其中匹配成功的 location 块中字符串长度最长的那一个。

题外话

之前一直以为 ^~ 是某种正则匹配,因为它有个代表正则匹配的 ~ 号,其实不是,是字符串类型的匹配,^~ 符号的含义感觉可以理解成 “不要正则匹配”,即匹配成功了就不用进行后续正则的匹配了,用以区分跟普通字符串匹配的区别。^ 就是 “非” 的意思,就是我们平常写的正则表达式里方括号里面的 ^ 标识符。