Nginx 的 location 语法为:
location [ = | ~ | ~* | ^~ ] uri { ... }
uri 中的 %xx
内容会被解码后进行匹配。
匹配修饰符虽然有四种,但其实匹配算法只有两种:前缀匹配 和 正则表达式匹配。
以 ~
开头的是正则匹配,带不带 *
的区别仅在于是否区分大小写——带星号不区分。
类似 location /
这样没有修饰符的是前缀匹配。
正则表达式的 uri 里可以写正则表达式,而前缀匹配的 uri 里就是普通的路径。
对于一个 uri,匹配 location 的逻辑是:
- 先进行前缀匹配,找到匹配前缀最长的一个 location,记为 foo,但并不使用
- 然后进行正则匹配,按配置文件内的书写顺序轮流匹配,若匹配成功就 break,并使用该正则匹配;若全部都匹配不上,就使用第一步里的 foo
最后解释 ^~
和 =
的作用。这两个修饰符是用来修改匹配逻辑的。
- 如果在第一步找到的最长 location(foo)使用了
^~
修饰符,那么跳过第二步,直接使用 foo -
=
表示严格相等,如果在第一步中成功匹配了此类规则,则直接跳过接下来的全部步骤,直接使用此 location,就是连最长匹配也不找了(实际这就是最长匹配)
其实从规则来看,对于精确匹配的需求,^~
完全可以实现,那么为什么还需要一个 =
呢?比如考虑下面的例子:假如我有一个主页文件 /index.html
,那么我写 ^~ /index.html
和 = /index.html
其实最终效果是一样的。
官方文档对等号的解释是:对于访问占比特别大的路径来说,用 =
匹配速度会更快些。
至于为什么快,可能得去看下源码了。大家也可以自己思考一下步骤一,如果让你来写你会怎么实现。在此实现的基础上再考虑精确匹配的需求,能不能达到效率最优。如果不能,那么 =
这个修饰符的存在就是合理的。