Nginx Location 规则解析:深入剖析 Location 优先级匹配机制

Nginx Location是什么?

Nginx接受到的请求后,请求发送到什么地方是有Nginx locaiton来定义的。

Nginx Location 规则

语法如下:

location optional_modifier location_match {
    . . .
}
类型 功能修饰符 示例
前缀字符串 None
=
^~
location /prefix
location = /exactmatch
location ^~ /longestmatchnotcheckreg
正则表达式 ~
~*
location ~ /regularsensitive
locaiton ~* /regularinsensitive

Location匹配优先级(官方文档)

以下是nginx文档中location的匹配过程,英文加上翻译。

步骤 English 中文
1 Test the URI against all prefix strings. 将 URI 与所有前缀字符串进行匹配。
2 The = (equals sign) modifier defines an exact match of the URI and a prefix string. If the exact match is found, the search stops. "=(等号) 修饰符用于精确匹配 URI 和前缀字符串。如果找到精确匹配,搜索停止。
3 If the ^~ (caret-tilde) modifier prepends the longest matching prefix string, the regular expressions are not checked. 如果 “^~(插入波浪号)” 修饰符前置于最长匹配的前缀字符串,将不会检查正则表达式。
4 Store the longest matching prefix string. 存储最长匹配的前缀字符串。
5 Test the URI against regular expressions. 将 URI 与正则表达式进行匹配。
6 Stop processing when the first matching regular expression is found and use the corresponding location. 当找到第一个匹配的正则表达式时停止处理,并使用相应的位置。
7 If no regular expression matches, use the location corresponding to the stored prefix string. 如果没有匹配的正则表达式,使用与存储的前缀字符串相对应的位置。

Location 匹配优先级(通俗讲解)

文档中写的比较简洁,理解起来可能有些问题。下面是我总结的比较通俗的讲解:

  1. 先匹配前缀表达式,后匹配正则表达式。
  2. 前缀表达式如果匹配到严格匹配 location = /exactmatch, 则直接结束;
  3. 前缀表达式命中多条,则选择最长的, 如果最长的有正则中止修饰符 location ^~ /longestmatchnotcheckreg , 则结束;
  4. 顺序匹配正则表达式,一但匹配,则结束;
  5. 上面的正则表达式没有匹配到,则使用前面第三步最长的那条前缀规则,并结束;
  6. 什么也没有,就只好使用默认的;
类型 功能修饰符 示例 匹配规则
前缀字符串 None
=
^~
location /prefix
location = /exactmatch
location ^~ /longestmatchnotcheckreg
匹配到则直接命中
匹配到且为最长前缀则命中
匹配到且最长,然后没有正则命中 ,该规则才命中
正则表达式 ~
~*
location ~ /regularsensitive
locaiton ~* /regularinsensitive
匹配到的第一个

注意点

大小写敏感~ 和大小写不敏感 ~*可能在一些系统上并不能正常工作,比如windows,debian对下面的匹配是不同的。/Abc 在windows上匹配到的是 /abc, 而debian 则匹配到的是 /Abc。 说明windows在这里对大小写的处理不是太敏感。
如果需要让windows也区分大小写,可以将第一个的规则修改为 location ~ (?-i)/abc 其中这里使用了regex modifiers (?-i)来关闭大小写不敏感。

location ~ /abc{
    return 200 /abc;
}
location ~* /Abc{
     return 200 /Abc;
}

示例

location  /a{
    return 200 prefix:a;
}
location =  /abc {
    return 200 prefix:exact;
}
location ^~ /abcd {	
    return 200 prefix:ab:withRegStop;
}
location  /abcde{	
    return 200 prefix:abcde;
}
location ~ /ab {
    return 200 regular:ab;
}
location ~ /abcd {
    return 200 regular:abcd;
}

curl 请求结果

# 匹配到前缀 /a, 仅匹配到一个,则为最终结果
$curl -sS pma.test/a
prefix:a

# 匹配到最长前缀 /a,不是完全匹配,也没有正则中止符,因此继续正则匹配,匹配到 ~ /ab
$curl -sS pma.test/ab  
regular:ab

# 匹配到前缀 /a, = /abc, 因为/abc完全匹配,因此最终为 = /abc
$ curl -sS pma.test/abc
prefix:exact

# 匹配到前缀 /a, ^~ /abcd, 没有完全匹配,最长匹配为 /abcd, 同时又正则终止符,因此最终结果为 ^~ /abcd
$ curl -sS pma.test/abcd
prefix:ab:withRegStop

# 匹配到前缀 /a, ^~ /agcd, /abcde, 没有完全匹配,因此最长前缀匹配是 /abcde, 但是没有正则终止符,则继续正则匹配,匹配到的第一个正则为 ~ /ab, 因此最终结果为 ~ /ab
$ curl -sS pma.test/abcde
regular:ab

# 与上面一样
$ curl -sS pma.test/abcdef
regular:ab

参考:

  1. nginx locaiton doc
  2. regex modifiers