Nginx(六) Nginx location 匹配顺序及优先级深究(亲测有效)

        Nginx配置文件详解请参考另一篇文章 Nginx(三) 配置文件详解 

        本篇文章主要是探讨Nginx location的匹配顺序,依照惯例,我们还是先贴结论再看测试结果。

配置顺序

        配置location时,需要注意正则表达式location的配置顺序。因为正则表达式匹配没有最长匹配策略,而是只要匹配成功就立刻终止匹配,所以配置顺序会影响匹配结果。而其它匹配规则不受配置顺序影响。

        当我们配置某个/uri的location时,尽量不要同时使用通用匹配和“指定字符串开头”的匹配,不然会搞乱自己的配置思路,容易分不清匹配优先级。

# 注意,这两个location是冲突的,二者只能存其一。
location /test {
    ···
}

location ^~ /test {
    ···
}

优先级

       结合所有测试结果,我们先对各种匹配规则的作用优先级做个排序

优先级排序 匹配规则 修饰符
1 精确匹配 =
2 指定字符串开头 ^~
3 正则匹配

~、~* 、!~、!~*、~* \.(gif|jpg|jpeg)$、~* /js/.*/\.js

4 通用匹配 /

         注意:1.默认情况下,“指定字符串开头”匹配规则的优先级确实比正则表达式高。但是,当请求URI前缀与某个通用匹配location完全匹配时,Nginx是永远也不会匹配到"^~"的(即使"^~"的匹配长度是最长的),而是先匹配正则表达式,再进行通用匹配,所以“指定字符串开头”匹配规则的优先级比正则表达式高并不是绝对的(参考测试2 - 测试8)

                    2.“指定字符串开头”匹配规则和通用匹配有最长匹配策略的,并不是匹配到就终止匹配;

匹配顺序

        匹配location的过程,其实可以理解成一个在众多选项中寻找最佳答案的过程。当然,“=”代表的就是正确答案,而其它情况只是相对于正确答案的最佳选项,如果有正确答案就选正确答案,如果没有就只能选择最佳答案,所以,严格意义上来说,我们只需要关注“以指定字符串开头”、正则表达式和通用匹配这三者之间的匹配顺序。下面我们来看具体的匹配顺序:

        stp1.按序匹配完所有location。Nginx按照location配置顺序依次匹配完所有location,每次匹配完都会进行记录比较(仅记录通用匹配),如果匹配的长度比记录中的长,就覆盖记录。

        stp2.精确匹配。如果在第一步的匹配过程中,与"="location匹配成功,则立刻终止匹配参考测试1

        stp3.检查请求URI前缀是否与某个通用匹配location完全匹配。如果没有这种情况,那么“指定字符串开头”匹配规则的优先级要比正则表达式高,Nginx此时会优先匹配"^~",再匹配正则表达式。如果有这种情况,Nginx不再匹配"^~"(即使"^~"的匹配长度是最长的),而是直接去匹配正则表达式。所以stp3是一个确认“指定字符串开头”和正则表达式匹配规则优先级的过程。参考测试2-测试9

        stp4.当“指定字符串开头”匹配规则的优先级比正则表达式高时,Nginx才开始匹配"^~"。如果跟某个"^~"location匹配成功,并不会立刻停止匹配,而是要继续匹配完所有"^~"最长匹配策略,直到找到与"^~"匹配长度最长的那个location后才停止匹配。所以,既然有最长匹配策略,那么在配置文件中,"^~"location的配置顺序并不会影响最终匹配结果。参考测试3、4、5、7

        stp5.当"指定字符串开头"匹配失败或正则表达式匹配规则的优先级比“指定字符串开头”高时,Nginx才开始匹配正则表达式。此时,Nginx会按照配置文件中正则表达式location的配置顺序依次完成匹配,只要匹配到就立刻停止匹配。参考测试2、6、8、11、12

        stp6.当"指定字符串开头"和正则表达式都匹配失败时,则在通用匹配中选择匹配长度最长的那个location最长匹配策略参考测试9、10

        stp7.当通用匹配都匹配失败时,只能选择"/"location了。

下面,我们开始测试。基本配置如下

http {
    log_subrequest on;				# 开启将子请求日志记录到access.log中
    log_format format2 escape=json '{'
    					'"SN":"$sn",'                     #自定义变量sn 
					    '"http_host":"$http_host",'
					    '"remote_addr":"$remote_addr",'
					    '"time_iso8601":"$time_iso8601",'
					    '"request":"$request",'
				    	'"http_referer":"$http_referer",'
				    	'"request_time":"$request_time",'
			    		'"request_length":"$request_length",'
			    		'"status":"$status",'
			    		'"bytes_sent":"$bytes_sent",'
			    		#'"body_bytes_sent":"$body_bytes_sent",'
			    		'"user_agent":"$http_user_agent",'
				      '}';
    
    absolute_redirect on;
    server_name_in_redirect off;
    port_in_redirect on; 
    
    server {
        listen 8688;
        server_name www.read********.cn;
        access_log  logs/access.log  format2;
        error_log  logs/error.log  notice;	# 将error_log日志级别修改为notice,否则rewrite log无法记录。
        rewrite_log on;    # 开启记录请求重写日志,默认是关闭
        root pages;     # 根目录设置为psges,该目录下有index.html、test.html、one.html、two.html、three.html
        # 下面配置本次测试的指令
        ···
        ···
 
    }
}

测试1:精确匹配 "="

server {
    ···
 
    set $sn 8;
    location /tes {
        set $sn 101;
        rewrite ^(.*)$ /t101;
    }
    location /testla {                  # location102,通用匹配
        set $sn 102;
        rewrite ^(.*)$ /t102;
    }

    location ~ /test {                  # location201,正则表达式20x
        set $sn 201;
        rewrite ^(.*)$ /t201;
    }
    location ^~ /test {                 # location301,指定字符串开头
        set $sn 301;
        rewrite ^(.*)$ /t301;
    }

    location ^~ /testl {                # location302,指定字符串开头
        set $sn 302;
        rewrite ^(.*)$ /t302;
    }
    location ~* /testl {                # location202,正则表达式20x
        set $sn 202;
        rewrite ^(.*)$ /t202;
    }

    location ~* /testla {               # location203,正则表达式20x
        set $sn 203;
        rewrite ^(.*)$ /t203;
    }
    # 下面这个location会跟第二个location冲突
    #location ^~ /testla {
    #    set $sn 99;
    #    rewrite ^(.*)$ /t99;
    #}
    location = /testla {
        set $sn 401;
        rewrite ^(.*)$ /t401;
    }

    location / {
        index  index.html index.htm;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值