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,另外,@
是用作服务端内部的一种转发行为,很少用.。
匹配顺序
- 普通location 与正则 location 之间的匹配:选择出”普通location"的最大前缀匹配结果后,还需要继续搜索正则location。如果继续搜索的”正则location”也有匹配上的,那么”正则location”覆盖”普通location”的最大前缀匹配
- 普通location 之间:最大前缀匹配
- 正则与正则:按照正则location 在配置文件中的物理顺序(编辑顺序)匹配的,并且只要匹配到一条正则location,就不再考虑后面的.
- 只要在“普通location ”前面加上
^~
符号或者=
或者严格精确匹配结果就不再需要继续匹配”正则location(^ 表示“非”,~ 表示“正则”,字符意思是:不要继续匹配正则)。^~
和=
:共同点为,都可以阻止继续匹配;不同点是^~
依然遵守“最大前缀”匹配规则,然而=
不是“最大前缀”,而是必须是严格匹配(exact match )
详细描述:
“普通location ”与“正则location ”之间的匹配规则是:先匹配普通location ,再匹配正则location 。那么,“普通location ”内部(普通location 与普通location)是如何匹配的呢?简单的说:最大前缀匹配。意思是普通location先匹配,而且选择了最大前缀匹配后,不能就停止后面的匹配,最大前缀匹配只是一个临时的结果,nginx还需要继续检查正则location。
正则location ”与“正则location”内部的匹配规则是:按照正则location 在配置文件中的物理顺序(编辑顺序)匹配的(这句话就说明location 并不是一定跟顺序无关,只是普通location与顺序无关,正则location 还是与顺序有关的),并且只要匹配到一条正则location ,就不再考虑后面的(这与“普通location”与“正则location”之间的规则不一样, “普通location”与“正则location”之间的规则是:选择出“普通location ”的最大前缀匹配结果后,还需要继续搜索正则location )。
最大前缀匹配,如果继续搜索的“正则location”也有匹配上的,那么“正则location”会覆盖“普通location”的最大前缀匹配(因为有这个覆盖关系,所以造成有些同学以为正则location先于普通location执行的错误理解)
通常的规则是,匹配完了“普通location”指令,还需要继续匹配“正则location”,但是你也可以告诉Nginx:匹配到了“普通location”后,不再需要继续匹配“正则location”了,要做到这一点只要在“普通location”前面加上
^~
符号(^
表示“非”,~
表示“正则”,字符意思是:不要继续匹配正则)。除了上面的
^~
可以阻止继续搜索正则location 外,还可以使用=
。那么如果^~
和=
都能阻止继续搜索正则location 的话,那它们之间有什么区别呢? 区别很简单,共同点是它们都能阻止继续搜索正则location,不同点是^~
依然遵守“最大前缀”匹配规则,然而=
不是“最大前缀”,而是必须是严格匹配(exact match )。
总结
- 所有类型location存在时,“=”匹配 > “^~”匹配(不是用正则,最大前缀匹配) > 正则匹配 > 普通(最大前缀匹配)> 默认(/)
- 正则 location 匹配让步普通 location 的严格精确匹配结果;但覆盖普通 location 的最大前缀匹配结果
- 还有一种“隐含”的方式来阻止正则 location 的搜索,这种隐含的方式就是:当“最大前缀”匹配恰好就是一个“严格精确(exact match )”匹配,照样会停止后面的搜索
location / {} 和 location =/ {}的区别
-
location / {}
遵守普通location 的最大前缀匹配,由于任何URI 都必然以/
根开头,所以对于一个URI ,如果有更specific 的匹配,那自然是选这个更specific 的,如果没有,/
一定能为这个URI 垫背(至少能匹配到/
),也就是说location / {}
有点默认配置的味道,其他更specific的配置能覆盖 overwrite 这个默认配置(这也是为什么我们总能看到location / {}
这个配置的一个很重要的原因)。 -
而
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/
}