location指令匹配一个uri,然后将该location的配置应用在这个uri上。
Syntax:
location [ = | ~ | ~* | ^~ ] uri { ... }
location @name { ... }
1.1. 匹配过程
匹配是对一个标准化后的URI上执行的,标准化的URI解码了'%XX',解析了相对路径.和..,并且将相连的反斜杠删到只剩一个等(前提是打开了merge_slashes选项)。
匹配分精确匹配、前缀匹配和正则匹配,精确匹配当然就是一字不差的匹配(不过最后的反斜杠是什么样的处理还需要试验),如果找到了一个精确匹配,那么匹配停止,应用location配置,否则继续找前缀匹配。前缀匹配的匹配规则是最长匹配规则,找到最长匹配的那个后,nginx不会马上应用这个location配置,而是暂时将这个location记下来,继续做正则匹配。正则匹配如果匹配成功,那么先前记下来的前缀匹配的那个location配置就没用了,直接忽略,并应用这个正则匹配的location配置,否则,没有任何一个正则匹配成功的话,就应用之前记下来的前缀匹配的location。
上面是个基本流程,需要注意的地方有这些:
- 精确匹配的符号是=,不加符号是前缀匹配,精确匹配成功后会停止查找,直接应用精确匹配的location配置
- 正则匹配时如果有多个匹配都相符,那么最先在配置文件中出现的那个正则匹配获胜
@startuml
start
if (=精确匹配成功) then (yes)
:匹配完成;
stop
endif
if (最长前缀匹配成功) then (yes)
if (^~) then (yes)
:匹配完成;
stop
else (no)
:记下该匹配;
:继续正则匹配;
if (正则匹配成功) then (yes)
:匹配完成;
:应用该正则匹配;
stop
else (no)
:匹配完成;
:应用记住的最长匹配;
stop
endif
endif
else (no)
:开始正则匹配;
if (正则匹配成功) then (yes)
:匹配完成;
stop
else (no)
:匹配失败;
:返回404;
stop
endif
endif
@enduml
正则匹配中~表示大小写敏感的正则匹配,~*表示大小写不敏感的正则匹配,
1.2. 实践
- 能用精确匹配的一律用=精确匹配
- 不需要正则匹配的统一用^~来匹配,也就是前缀匹配都只负责前缀匹配,不走正则匹配流程
- 匹配到目录的一律后面加反斜杠/结尾
- 确实需要正则匹配的注意不要有重复的匹配规则,也就是一个URI最多被匹配到一个正则
PS:解释下第3条,比如我有一个/api/v1/abc/fi的匹配配置,实际上我是希望匹配/api/v1/abc/fi/*的uri,那如果有一个uri是/api/v1/abc/fiTest的话,这个uri也会匹配上/api/v1/abc/fi,这显然不是我们希望的,这就是为什么匹配到目录的一律后面加反斜杠。