文章目录
- 简介
- 语法
- 匹配规则分类
- 匹配流程
- 匹配优先级
- 官网示例
- 经典案例
- 案例一
- 案例二
- 参考链接
简介
location 是核心模块 ngx_http_core_module 提供的功能,为了将他的用法搞清楚,我们把官网的例子拿来试验
语法
语法: location [ = | ~ | ~* | ^~ | ] uri {...}
location @name {...}
可以用在 server,location 中
匹配规则分类
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作为成功匹配的路线
匹配优先级
匹配的顺序是先进行普通匹配,然后再进行正则匹配
匹配的优先级是
"=" > "^~" > "~" > "~*" > /
官网示例
location = / {
[ configuration A ]
}
location / {
[ configuration B ]
}
location /documents/ {
[ configuration C ]
}
location ^~ /images/ {
[ configuration D ]
}
location ~* \.(gif|jpg|jpeg)$ {
[ configuration E ]
}
说明
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中
案例二
- 背景
nginx请求中,所有以.gif .gpg .jpeg结尾的文件都进行某段逻辑处理
但是 /images/xx.gif 这个请求却无法匹配 - 实现方案
location ~ /images {
return 200 "/images";
}
location ~* \.(gif|jpg|jpeg)$ {
return 200 "$request_uri";
}
[root@base-images-factory conf]# curl 127.0.0.1/images/123;echo
/images
[root@base-images-factory conf]# curl 127.0.0.1/a/1.jpg;echo
/a/1.jpg
[root@base-images-factory conf]# curl 127.0.0.1/images/123.jpg;echo
/images
- 结论
很显然, 配置文件中都是正则匹配, 匹配规则是顺序匹配,那么/images/xx.jpg这样的请求在碰到 ~/images
的时候就会被拦下来,显然到不了 ~* \.(gif|jpg|jpeg)$
这一层