您的位置:首页 > 运维架构 > Nginx

nginx location的正则匹配规则

2017-08-08 11:29 218 查看
nginx location的正则匹配规则

location匹配命令

 

~      #波浪线表示执行一个正则匹配,区分大小写

~*    #表示执行一个正则匹配,不区分大小写

^~    #^~表示普通字符匹配,如果该选项匹配,则不再匹配别的选项,一般用来匹配目录,普通匹配

=      #进行普通字符精确匹配,精确匹配后不会再继续任何别的匹配了,普通匹配

@     #"@" 定义一个命名的 location,使用在内部定向时,例如 error_page, try_files,普通匹配

#普通匹配中,不能使用通配符,例如^~普通匹配就不能使用通配符,目前至少已经验证($)不能用在普通匹配上,nginx -t会通过,但实际不生效

#想使用(.*)(^)($)等通配符,就需要使用正则匹配

#生产环境中尽量只使用正则,避免复杂

        location ~* /mobile/api/log$ {

            proxy_pass                  http://new_preevaluate;

            proxy_http_version          1.1;

            proxy_set_header            Connection "";

        }

 

location 匹配的优先级(与location在配置文件中的顺序无关)

= 精确匹配会第一个被处理。如果发现精确匹配,nginx停止搜索其他匹配。

普通字符匹配(即没有任何匹配符号,比如location /static),正则表达式规则和长的块规则将被优先和查询匹配,也就是说如果该项匹配还需去看有没有正则表达式匹配和更长的匹配。

^~ 则只匹配该规则,nginx停止搜索其他匹配,否则nginx会继续处理其他location指令。

最后匹配理带有"~"和"~*"的指令,如果找到相应的匹配,则nginx停止搜索其他匹配;当没有正则表达式或者没有正则表达式被匹配的情况下,那么匹配程度最高的逐字匹配指令会被使用。

 

location 优先级官方文档

 

Directives with the = prefix that match the query exactly. If found, searching stops.

All remaining directives with conventional strings, longest match first. If this match used the ^~ prefix, searching stops.

Regular expressions, in order of definition in the configuration file.

If #3 yielded a match, that result is used. Else the match from #2 is used.

=前缀的指令严格匹配这个查询。如果找到,停止搜索。

所有剩下的常规字符串,最长的匹配。如果这个匹配使用^〜前缀,搜索停止。

正则表达式,在配置文件中定义的顺序。

如果第3条规则产生匹配的话,结果被使用。否则,如同从第2条规则被使用。

location  = / {

  [ configuration A ]

}

  # 只匹配"/".

location  / {

  [ configuration B ]

}

  # 匹配任何请求,因为所有请求都是以"/"开始

  # 但是更长字符匹配或者正则表达式匹配会优先匹配

location ^~ /images/ {

  [ configuration C ]

}

  # 匹配任何以 /images/ 开始的请求,并停止匹配 其它location

location ~* .(gif|jpg|jpeg)$ {

  [ configuration D ]

}

  # 匹配以 gif, jpg, or jpeg结尾的请求.

  # 但是所有 /images/ 目录的请求将由 [Configuration C]处理.  注意是和上面那条一起进行关联说明的的

请求URI例子:

/      

##符合configuration A

/documents/document.html 

##符合configuration B

/images/1.gif 

##符合configuration C

/documents/1.jpg 

##符合 configuration D

@location 例子

error_page 404 = @fetch;

 

location @fetch(

proxy_pass http://fetch;
)

 

关于一些对location认识的误区

 

 

1、 location 的匹配顺序是"先匹配正则,再匹配普通"。

 

 

 

矫正: location 的匹配顺序其实是"先匹配普通,再匹配正则"。造成这种误解的原因是:正则匹配会覆盖普通匹配(实际的规则,比这复杂,后面会详细解释)。

 

 

 

2、 location 的执行逻辑跟 location 的编辑顺序无关。

 

 

 

"普通 location"的匹配规则是"最大前缀",因此"普通 location"的确与location 编辑顺序无关;

 

但是"正则 location"的匹配规则是"顺序匹配,且只要匹配到第一个就停止后面的匹配";

 

"普通location"与"正则 location"之间的匹配顺序是先匹配普通 location ,再"考虑"匹配正则 location 

 

注意这里的"考虑"是"可能"的意思,也就是说匹配完"普通 location"后,有的时候需要继续匹配"正则 location",有的时候则不需要继续匹配"正则 location"

 

两种情况下,不需要继续匹配正则 location :

 

( 1 )当普通 location 前面指定了"^~",特别告诉 Nginx 本条普通 location 一旦匹配上,则不需要继续正则匹配;

 

( 2 )当普通location 恰好严格匹配上,不是最大前缀匹配,则不再继续匹配正则。

 

 

 

总结一句话:  "正则 location 匹配让步普通 location 的严格精确匹配结果;但覆盖普通 location 的最大前缀匹配结果"

  

##location proxy_pass 不会改变URL的主机名称,会保持访问的主机地址不变,跟rewrite不一样

  

1 、尽管location 的/uri/ 配置一样,但前缀不一样,表达的是不同的指令含义

 

2 、查询字符串不在URI范围内。例如:/films.htm?fid=123 的URI 是/films.htm

 

 

   

正则location和普通location 

 

那么其中"~"和"~*"前缀表示正则location ,"~"区分大小写,"~*"不区分大小写;

 

其他前缀(包括:"=","^~"和"@")和无任何前缀的都属于普通location 。

  

对于一个特定的 HTTP 请求nginx 应该匹配哪个 location 块的指令呢

 

匹配 规则是:先匹配普通location,再匹配正则表达式

 

注意:官方文档这句话就明确说了,先普通location ,而不是有些同学的误区"先匹配正则location"。

  

前面说了"普通location"与"正则location"之间的匹配规则是:

 

先匹配普通location ,再匹配正则location 。那么,"普通location"内部(普通location 与普通location )是如何匹配的呢?

 

简单的说:最大前缀匹配

 

因为location 不是"严格匹配",而是"前缀匹配",就会产生一个HTTP 请求,可以"前缀匹配"到多个普通location 

 

例如:

 

location /prefix/mid/ {} 

 



 

location /prefix/ {} 

 

 

对于HTTP 请求/prefix/mid/t.html ,前缀匹配的话两个location 都满足,选哪个?

 

原则是:the most specific match ,于是选的是location /prefix/mid/ {}

 

 

普通location 先匹配,而且选择了最大前缀匹配后,不能就停止后面的匹配,最大前缀匹配只是一个临时的结果,nginx 还需要继续检查正则location 

 

 

"正则location " 与 "正则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 的最大前缀匹配,由于任何URI 都必然以"/ "根开头

 

所以对于一个URI ,如果有更specific 的匹配,那自然是比这个更specific 的

 

如果没有,"/ "一定能为这个URI 垫背(至少能匹配到"/ ")

 

也就是说"location / {} "有点默认配置的味道,其他更specific的配置能覆盖overwrite 这个默认配置

 

这也是为什么我们总能看到location / {} 这个配置的一个很重要的原因

 

 

而"location = / {} "遵守的是"严格精确匹配exact match "

 

也就是只能匹配 http://host:port/ 请求,同时会禁止继续搜索正则location

 

因此如果我们只想对"GET / "请求配置作用指令,那么我们可以选"location = / {} "

 

这样能减少正则location 的搜索,因此效率比"location / {}" 高

 

前提是我们的目的仅仅只想对"GET / "起作用

  

前面我们说了,普通location 匹配完后,还会继续匹配正则location ;但是nginx 允许你阻止这种行为

 

方法很简单,只需要在普通location 前加"^~ "或"= "

 

但其实还有一种"隐含"的方式来阻止正则location 的搜索,这种隐含的方式就是:

 

当"最大前缀"匹配恰好就是一个"严格精确(exact match )"匹配,照样会停止后面的搜索

 

只要遇到"精确匹配exact match ",即使普通location 没有带"= "或"^~ "前缀,也一样会终止后面的匹配

 

 

 

假设当前配置是:

 

 

location /exact/match/test.html 

 

{ 配置指令块1}

 

 

location /prefix/ 

 

{ 配置指令块2} 

 

 

location ~ \.html$ 

 

{ 配置指令块3} 

 

 

如果我们请求 GET /prefix/index.html ,则会被匹配到指令块3 

 

因为普通location /prefix/ 依据最大匹配原则能匹配当前请求,但是会被后面的正则location 覆盖

 

当请求GET /exact/match/test.html ,会匹配到指令块1 ,因为这个是普通location 的exact match ,会禁止继续搜索正则location 。

 

 

 

正则 location 匹配让步普通location 的严格精确匹配结果;但覆盖普通 location 的最大前缀匹配结果"

  

Example:

 

 

 

location   = / {

 

[ configuration A ]

 

}

 

 

 

location   / {

 

[ configuration B ]

 

}

 

 

 

location ^~ /images/ {

 

[ configuration C ]

 

}

 

 

 

location ~* \.(gif|jpg|jpeg)$ {

 

[ configuration D ]

 

}

 

 

 

location / {} 能够匹配所有HTTP 请求,因为任何HTTP 请求都必然是以‘/ ’开始的

 

但是,正则location 和其他任何比‘/ ’更长的普通location会优先匹配

 

(location / {} 是普通location 里面最短的,因此其他任何普通location 都会比它更长,当然location = / {} 和 location ^~ / {} 是一样长的)

   

location 的语法中,可以有"= ","^~ ","~ "和"~* "前缀,或者干脆没有任何前缀,还有"@ "前缀,但是后面的分析我们始终没有谈到"@ "前缀

 

文章最后点内容,介绍了"@"的用途:"@ "是用来定义"Named Location "的(你可以理解为独立于"普通location (location using literal strings )"和"正则location (location using regular expressions )"之外的第三种类型),这种"Named Location "不是用来处理普通的HTTP 请求的,它是专门用来处理"内部重定向(internally redirected )"请求的。注意:这里说的"内部重定向(internally
redirected )"或许说成"forward "会好点,以为内internally redirected 是不需要跟浏览器交互的,纯粹是服务端的一个转发行为。

   

 

  

 "@" 前缀 Named Location 使用

 

       #error_page 404 http://www.baidu.com # 直接这样是不允许的

 

       error_page 404 = @fallback;

 

       location @fallback {

 

           proxy_pass http://www.baidu.com;
 

       }

 

 

配置文件的意思是:如果请求的 URI 存在,则本 nginx 返回对应的页面;如果不存在,则把请求代理到baidu.com 上去做个弥补(注: nginx 当发现 URI 对应的页面不存在, HTTP_StatusCode 会是 404 ,此时error_page 404 指令能捕获它)。

 

 

 

当 curl http://localhost:9090/duty/ -i 时, nginx 没找到对应的页面,于是 error_page = @fallback ,把请求代理到 baidu.com 。注意这里的 error_page = @fallback 不是靠重定向实现的,而是所说的" internally redirected (forward )"。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: