location 是核心模块 ngx_http_core_module 提供的功能,为了将他的用法搞清楚,我们把官网的例子拿来试验
location对格式化后的uri 根据给很粗的匹配规则进行匹配 请求的uri中可能存在的多个斜杠,格式化过程中,会被压缩成一个斜杠,比如//test//a///b 会压缩成/test/a/b
location可以设置两种匹配规则 前缀字符串和正则表达式
前缀字符串即直接把location /后面的字符串拿来匹配uri中的信息,遵循最长匹配规范,啥叫最长匹配规范,就是所有的前缀字符串都匹配一遍,能匹配上最长的字符串,作为候选
= 精确匹配前缀字符串,匹配到后不再进行任何匹配操作^~ 遵循最长匹配规则,匹配前缀字符串,匹配到后,不再进行正则匹配 正则表达式是一组符合正则语法规范的字符串,用来匹配指定的uri包括
~ 大小写敏感匹配~* 大小写不敏感匹配类似于grep -i首先判断是否有=号精准匹配满足uri的需求,如果有的话,直接跳出匹配
全部匹配一遍用前缀字符串设置的location规则,类似 location /test location = /test location ^~ /test这样色儿的,将他们全部匹配一遍后,其中可以匹配uri,且拥有最长字符串的location规则将被选中,被记录下来
查看最长匹配的location 的修饰符是否是 ^~ 如果是的话,匹配成功,不再进行后续的正则匹配
从上到下,按照顺序进行正则匹配,匹配成功一个,即跳出匹配
如果正则匹配没有匹配到location 则走第2步中记录的最长匹配记录的location作为成功匹配的路线
匹配的顺序是先进行普通匹配,然后再进行正则匹配
匹配的优先级是
"=" > "^~" > "~" > "~*" > /说明
The “/” request will match configuration A, the “/index.html” request will match configuration B the “/documents/document.html” request will match configuration C the “/images/1.gif” request will match configuration D the “/documents/1.jpg” request will match configuration E.业务nginx中已经存在了一个~ /test的正则location配置,而现在又有了新需求,需要配置一个/test-be的location,我随便按照之前 /test 的配方配了一个,结果踩到了坑里面,无论怎么访问,请求都到不了服务!经过排查,发现所有请求都进了/test的lacation中,百思不得其解
实现方案 第一种 正则匹配 /test 普通匹配 /test-be ## nginx 配置 location ~ /test { return 200 "/test"; } location /test-be { return 200 "/test-be"; } ##测试结果 [root@base-images-factory conf]# curl 127.0.0.1/test;echo /test [root@base-images-factory conf]# curl 127.0.0.1/test-be;echo /test 第二种 都用正则匹配 ## nginx 配置 location ~ /test { return 200 "/test"; } location ~ /test-be { return 200 "/test-be"; } ##测试结果 [root@base-images-factory conf]# curl 127.0.0.1/test;echo /test [root@base-images-factory conf]# curl 127.0.0.1/test-be;echo /test 第三种 更换正则匹配的顺序 ## nginx 配置 location ~ /test-be { return 200 "/test-be"; } location ~ /test { return 200 "/test"; } ## 测试结果 [root@base-images-factory conf]# curl 127.0.0.1/test;echo /test [root@base-images-factory conf]# curl 127.0.0.1/test-be;echo /test-be 第四种 用 ^~ 来匹配 ## nginx 配置 location ~ /test { return 200 "/test"; } location ^~ /test-be { return 200 "/test-be"; } #测试结果 [root@base-images-factory conf]# curl 127.0.0.1/test;echo /test [root@base-images-factory conf]# curl 127.0.0.1/test-be;echo /test-be 总结可以看到,只有第三种和第四种 方案实现了我们的目的,那么原因呢?
其实看过上面的匹配流程,在看着案例就很简单了
方案 第一种 uri=/test-be 进行全局前缀字符串匹配 显然 location /test-be在第一轮中,已经被匹配到,作为候选location已经被选中,不幸的是在接下来的正则匹配环节 ~ /test也命中了,直接胜出,导致/test-be的请求,转发到了/test的location下
方案第二种 显然在第一轮前缀匹配的过程中,是没有命中的,然后进入第二轮正则匹配,由于是按照顺序匹配首先会碰见/test 结果直接匹配成功,直接调出匹配,使得/test-be的请求再次落入了/test location的陷阱
方案第三种 结合方案第二种的分析,很容易能够得出为什么方案三是可以正确匹配到/test-be的
方案第四种 由于 location 定义 /test-be 用了 ^~修饰符,那么在第一轮前缀字符串匹配到后,将不再继续进行正则匹配,所以/test-be请求转发到 /test-be的location中
很显然, 配置文件中都是正则匹配, 匹配规则是顺序匹配,那么/images/xx.jpg这样的请求在碰到 ~/images的时候就会被拦下来,显然到不了 ~* \.(gif|jpg|jpeg)$ 这一层
http://nginx.org/en/docs/http/ngx_http_core_module.html#location
https://www.jianshu.com/p/38810b49bc29