Nginx 的 location 语法为:

location [ = | ~ | ~* | ^~ ] uri { ... }

uri 中的 %xx 内容会被解码后进行匹配。

匹配修饰符虽然有四种,但其实匹配算法只有两种:前缀匹配正则表达式匹配

~ 开头的是正则匹配,带不带 * 的区别仅在于是否区分大小写——带星号不区分。

类似 location / 这样没有修饰符的是前缀匹配。

正则表达式的 uri 里可以写正则表达式,而前缀匹配的 uri 里就是普通的路径。

对于一个 uri,匹配 location 的逻辑是:

  1. 先进行前缀匹配,找到匹配前缀最长的一个 location,记为 foo,但并不使用
  2. 然后进行正则匹配,按配置文件内的书写顺序轮流匹配,若匹配成功就 break,并使用该正则匹配;若全部都匹配不上,就使用第一步里的 foo

最后解释 ^~= 的作用。这两个修饰符是用来修改匹配逻辑的。

  • 如果在第一步找到的最长 location(foo)使用了 ^~ 修饰符,那么跳过第二步,直接使用 foo
  • = 表示严格相等,如果在第一步中成功匹配了此类规则,则直接跳过接下来的全部步骤,直接使用此 location,就是连最长匹配也不找了(实际这就是最长匹配)

其实从规则来看,对于精确匹配的需求,^~ 完全可以实现,那么为什么还需要一个 = 呢?比如考虑下面的例子:假如我有一个主页文件 /index.html,那么我写 ^~ /index.html= /index.html 其实最终效果是一样的。

官方文档对等号的解释是:对于访问占比特别大的路径来说,用 = 匹配速度会更快些。

至于为什么快,可能得去看下源码了。大家也可以自己思考一下步骤一,如果让你来写你会怎么实现。在此实现的基础上再考虑精确匹配的需求,能不能达到效率最优。如果不能,那么 = 这个修饰符的存在就是合理的。