Nginx之location匹配规则

什么是location?

nginx就是通过拦截到的请求去对配置好的location块(location block)进行请求代理的。被代理的URL去对location后边的字符串(或正则)根据一定的规则进行匹配,然后执行对应location定义的操作。

location作用

location指令的作用是根据用户请求的URI来执行不同的应用,也就是根据用户请求的网站URL进行匹配,匹配成功即进行相关的操作。

一个server可以有多个location配置, 对于用户的请求在面对多个location时,需要一定的location匹配规则和location优先级来确定具体匹配到哪个location。

location语法规则

location [=|~|~*|^~] /uri/ { … }
# |指令|   | 前缀 |  |匹配的网站网址|  |匹配URI之后要执行的配置段|
  • 1
  • 2
语法匹配规则
没有前缀 普通匹配(遵循最大前缀匹配规则)
= 精确(严格)匹配
^~ 非正则匹配(依然遵循最大前缀匹配规则)
~ 开头表示区分大小写的正则匹配
~* 开头表示不区分大小写的正则匹配
!~ 和 !~* 分别为区分大小写不匹配及不区分大小写不匹配的正则
/ 通用匹配,任何请求都会匹配到。

location分类

两类:正则location和普通location

  • ~ 、~*!~!~* 为正则location
  • =^~@无任何前缀的都属于普通location,另外,@是用作服务端内部的一种转发行为,很少用.。

匹配顺序

  1. 普通location 与正则 location 之间的匹配:选择出”普通location"的最大前缀匹配结果后,还需要继续搜索正则location。如果继续搜索的”正则location”也有匹配上的,那么”正则location”覆盖”普通location”的最大前缀匹配
  2. 普通location 之间:最大前缀匹配
  3. 正则与正则:按照正则location 在配置文件中的物理顺序(编辑顺序)匹配的,并且只要匹配到一条正则location,就不再考虑后面的.
  4. 只要在“普通location ”前面加上^~符号或者=或者严格精确匹配结果就不再需要继续匹配”正则location(^ 表示“非”,~ 表示“正则”,字符意思是:不要继续匹配正则)。 ^~=:共同点为,都可以阻止继续匹配;不同点是^~依然遵守“最大前缀”匹配规则,然而=不是“最大前缀”,而是必须是严格匹配(exact match )

详细描述:

  1. “普通location ”与“正则location ”之间的匹配规则是:先匹配普通location ,再匹配正则location 。那么,“普通location ”内部(普通location 与普通location)是如何匹配的呢?简单的说:最大前缀匹配。意思是普通location先匹配,而且选择了最大前缀匹配后,不能就停止后面的匹配,最大前缀匹配只是一个临时的结果,nginx还需要继续检查正则location。

  2. 正则location ”与“正则location”内部的匹配规则是:按照正则location 在配置文件中的物理顺序(编辑顺序)匹配的(这句话就说明location 并不是一定跟顺序无关,只是普通location与顺序无关,正则location 还是与顺序有关的),并且只要匹配到一条正则location ,就不再考虑后面的(这与“普通location”与“正则location”之间的规则不一样, “普通location”与“正则location”之间的规则是:选择出“普通location ”的最大前缀匹配结果后,还需要继续搜索正则location )。

  3. 最大前缀匹配,如果继续搜索的“正则location”也有匹配上的,那么“正则location”会覆盖“普通location”的最大前缀匹配(因为有这个覆盖关系,所以造成有些同学以为正则location先于普通location执行的错误理解)

  4. 通常的规则是,匹配完了“普通location”指令,还需要继续匹配“正则location”,但是你也可以告诉Nginx:匹配到了“普通location”后,不再需要继续匹配“正则location”了,要做到这一点只要在“普通location”前面加上^~符号(^表示“非”,~表示“正则”,字符意思是:不要继续匹配正则)。

  5. 除了上面的^~可以阻止继续搜索正则location 外,还可以使用=。那么如果^~=都能阻止继续搜索正则location 的话,那它们之间有什么区别呢? 区别很简单,共同点是它们都能阻止继续搜索正则location,不同点是^~依然遵守“最大前缀”匹配规则,然而=不是“最大前缀”,而是必须是严格匹配(exact match )。

总结

  1. 所有类型location存在时,“=”匹配 > “^~”匹配(不是用正则,最大前缀匹配) > 正则匹配 > 普通(最大前缀匹配)> 默认(/)
  2. 正则 location 匹配让步普通 location 的严格精确匹配结果;但覆盖普通 location 的最大前缀匹配结果
  3. 还有一种“隐含”的方式来阻止正则 location 的搜索,这种隐含的方式就是:当“最大前缀”匹配恰好就是一个“严格精确(exact match )”匹配,照样会停止后面的搜索

location / {} 和 location =/ {}的区别

  1. location / {}遵守普通location 的最大前缀匹配,由于任何URI 都必然以/根开头,所以对于一个URI ,如果有更specific 的匹配,那自然是选这个更specific 的,如果没有,/一定能为这个URI 垫背(至少能匹配到 /),也就是说location / {}有点默认配置的味道,其他更specific的配置能覆盖 overwrite 这个默认配置(这也是为什么我们总能看到location / {}这个配置的一个很重要的原因)。

  2. location = / {}遵守的是“严格精确匹配exact match ”,也就是只能匹配 http://host:port/ 请求,同时会禁止继续搜索正则location 。因此如果我们只想对“GET / ”请求配置作用指令,那么我们可以选location = / {}这样能减少正则location 的搜索,因此效率比location / {}高(注:前提是我们的目的仅仅只想对“GET / ”起作用)。

示例:

location = / {
 # 精确匹配 / ,主机名后面不能带任何字符串
 [ configuration A ]
}
 
location / {
 # 因为所有的地址都以 / 开头,所以这条规则将匹配到所有请求
 # 但是正则和最长字符串会优先匹配
 [ configuration B ]
}
 
location /documents/ {
 # 匹配任何以 /documents/ 开头的地址,匹配符合以后,还要继续往下搜索
 # 只有后面的正则表达式没有匹配到时,这一条才会采用这一条
 [ configuration C ]
}
 
location ~ /documents/Abc {
 # 匹配任何以 /documents/Abc 开头的地址,匹配符合以后,还要继续往下搜索
 # 只有后面的正则表达式没有匹配到时,这一条才会采用这一条
 [ configuration C ]
}
 
location ^~ /images/ {
 # 匹配任何以 /images/ 开头的地址,匹配符合以后,停止往下搜索正则,采用这一条。
 [ configuration D ]
}
 
location ~* \.(gif|jpg|jpeg)$ {
 # 匹配所有以 gif,jpg或jpeg 结尾的请求
 # 然而,所有请求 /images/ 下的图片会被 config D 处理,因为 ^~ 到达不了这一条正则
 [ configuration E ]
}
 
location /images/ {
 # 字符匹配到 /images/,继续往下,会发现 ^~ 存在
 [ configuration F ]
}
 
location /images/abc {
 # 最长字符匹配到 /images/abc,继续往下,会发现 ^~ 存在
 # F与G的放置顺序是没有关系的
 [ configuration G ]
}
 
location ~ /images/abc/ {
 # 只有去掉 config D 才有效:先最长匹配 config G 开头的地址,继续往下搜索,匹配到这一条正则,采用
  [ configuration H ]
}
 
location ~* /js/.*/\.js {
  [ configuration I ]
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

按照上面的location写法,以下的匹配示例成立:

/ -> config A
精确完全匹配,即使/index.html也匹配不了

/downloads/download.html -> config B
匹配B以后,往下没有任何匹配,采用B

/images/1.gif -> configuration D
匹配到F,往下匹配到D,停止往下

/images/abc/def -> config D
最长匹配到G,往下匹配D,停止往下
可以看到 任何以/images/开头的都会匹配到D并停止,FG写在这里是没有任何意义的,H是永远轮不到的,这里只是为了说明匹配顺序

/documents/document.html -> config C
匹配到C,往下没有任何匹配,采用C

/documents/1.jpg -> configuration E
匹配到C,往下正则匹配到E

/documents/Abc.jpg -> config C
最长匹配到C,往下正则顺序匹配到C,不会往下到E

实际使用中,至少有三个匹配规则定义,如下:

#直接匹配网站根,通过域名访问网站首页比较频繁,使用这个会加速处理,官网如是说。
#这里是直接转发给后端应用服务器了,也可以是一个静态首页
# 第一个必选规则
location = / {
  proxy_pass http://tomcat:8080/index
}
# 第二个必选规则是处理静态文件请求,这是nginx作为http服务器的强项
# 有两种配置模式,目录匹配或后缀匹配,任选其一或搭配使用
location ^~ /static/ {
  root /webroot/static/;
}
location ~* \.(gif|jpg|jpeg|png|css|js|ico)$ {
  root /webroot/res/;
}
#第三个规则就是通用规则,用来转发动态请求到后端应用服务器
#非静态文件请求就默认是动态请求,自己根据实际把握
#毕竟目前的一些框架的流行,带.php,.jsp后缀的情况很少了
location / {
  proxy_pass http://tomcat:8080/
}
posted @ 2022-11-22 16:09  GaoYanbing  阅读(1811)  评论(0编辑  收藏  举报