Nginx的location规则迷之匹配
Nginx,一个改变世界的软件,其作者是一个俄罗斯人,俗称毛子,在国人的印象中,是一群晚饭后牵着大灰熊在小区楼下散步的彪汉。能写出这般顺滑的软件,可谓是心有猛虎细嗅蔷薇典型代表啊。 很多同学都被location规则绕得云里雾里,总是搞不清楚自己写的规则为什么没有生效。其实location复杂的匹配规则可以用一句话来概括——女生想用最省力的方法找合适的男生。好像更云里雾里了,且听我娓娓道来。
网上一些对location认识的误区我就不写在这里混淆视听了,直接写我认为是对的,而且确实是对的规则。
对于非正则匹配,nginx会检索完所有的非正则location条目,而正则匹配,nginx会在匹配到第一条正则后,停止检索。为什么被设计成这样?上文提到女生想用最省力的方法找合适的男生,计算机检索非正则匹配是非常轻松的,所以它会把非正则的所有条目都看完,而计算机检索正则匹配的时候,会进行大量的逻辑运算,这样很不省力,违背了nginx为高效而生的初衷,所以被设计为检索到第一条能匹配的正则就停止检索。这就说明了location 的执行逻辑跟 location 在配置文件里面的编辑顺序是有关系的。 上面的话换个说法: Nginx服务器会首先会检查多个location中是否有普通的uri匹配,如果有多个匹配,会先记住匹配度最高的那个。然后再检查正则匹配,这里切记正则匹配是有顺序的,从上到下依次匹配,一旦匹配成功,则结束检查,并就会使用这个location块处理此请求。如果正则匹配全部失败,就会使用刚才记录普通uri匹配度最高的那个location块处理此请求。
女生视角总结来说:她们会把那些条件比写得比较明确清晰的男生全都看完,找到一个最合适的做备胎(非正则匹配),然后她们会去看一眼那些条件看起来比较好,但写得比较模糊的,比如说就写了个某某公司总经理(正则匹配)一找到有合适的,则选之,不会再继续看那些后面的,若看完这些总经理都没找到合适的,用备胎。此时如果你头顶上有北上广本地土著的光环"^~",则会优先考虑。若你"="万达王公子,前面一切皆可抛啊。
总之;匹配优先规则如下:
➤优先级最高的是带有”=“修饰符的location区段,当请求的URI与指定的字符串精确匹配时,则nginx应用此段配置,不再看其他区段,女生视角来说,就是你刚好是王公子了。
➤第二优先级为带有"^~"的location区段,匹配到了“普通location ”后,不再需要继续匹配“正则location ”了,(^ 表示“非”,~ 表示“正则”,字符意思是:不要继续匹配正则)。女生视角来说,你是上海本地户口。
➤第三优先级为能匹配上的第一条正则匹配。女生视角来说,虽然你资料只写了个总经理,但颜值还不错,身高两米六。
➤第四优先级为不带修饰符的location区段,也就是普通字符串匹配。女生视角来说,前面那些正则都是画大饼的,还是去找备胎吧。
修饰符 |
说明 |
---|---|
= 王公子 |
URI的定位必须与指定的模式精确匹配。该模式在这里限定为一个简单的文本字符串,不能使用正则表达式: location = /abcd 这个配置语句: 能匹配上 https://hqidi.com/abcd (严格匹配) 能匹配上 https://hqidi.com/abcd?param1¶m2 (不管查询字符串参数) 不能匹配 https://hqidi.com/abcd/ (结尾斜杠) 不能匹配 https://hqidi.com/abcde (在指定的模式后添加额外的字符) |
^~ 上海土著 |
可以理解为禁止贪婪匹配,因为正常的匹配规则是匹配到字符串后(=号匹配除外),还不死心,还得去看看正则有没有能匹配上的,加上"^~"前缀后,匹配到字符串后就应用本条规则,不再去看正则。 |
~* |
不区分大小写的正则匹配。 location ~* ^/abcd$ 这个配置语句: 能匹配上 https://hqidi.com/abcd (严格匹配) 能匹配上 https://hqidi.com/ABCD 能匹配上 https://hqidi.com/abcd?param1¶m2 (不管查询字符串参数) 不能匹配 https://hqidi.com/abcd/(因为指定了正则表达式) 不能匹配 https://hqidi.com/abcde(额外字符,正则不匹配) |
~ |
客户端请求的URI与指定的正则表达式匹配必须区分大小写。 location ~ ^/abcd$ 这个配置语句: 能匹配上 https://hqidi.com/abcd (严格匹配) 不能匹配 https://hqidi.com/ABCD (区分大小写) 不能匹配 https://hqidi.com/abcd/(因为指定了正则表达式) 不能匹配 https://hqidi.com/abcde(额外字符,正则不匹配) |
(无) |
当匹配前缀是空的时候,URI的定位必须以指定模式开始,不可以使用正则表达式。 location /abcd 这个配置语句: 能匹配上 https://hqidi.com/abcd (严格匹配) 能匹配上 https://hqidi.com/abcd?param1¶m2 (不管查询字符串参数) 能匹配上 https://hqidi.com/abcd/ (结尾斜杠) 能匹配上 https://hqidi.com/abcde (在指定的模式后添加额外的字符) |
@ |
@是一个命名标记,这种location不会用于正常的请求,它们通常只用于处理内部的重定向(例如:error_page,try_file) |
nginx location实验部分
为了更清晰的说明实验,我用到了一个第三方的nginx模块"echo-nginx-module",模块安装请参考
主要配置文件如下:
#1
location /abcd {
echo "现在匹配到的是 location /abcd";
}
#2
location ~* /abcd {
echo "现在匹配到的是 location ~* /abcd";
}
#3
location ~ /abcd {
echo "现在匹配到的是 location ~ /abcd";
}
#4
location ~ /abc {
echo "现在匹配到的是 location ~ /abc";
}
#5
location ^~ /abc {
echo "现在匹配到的是 location ^~ /abc";
#6
location = /abcd {
echo "现在匹配到的是 location = /abcd";
}
当配置文件如上所示时:
匹配到了带“=”号前缀的location区段,所以得出结论,当请求的URI与指定的字符串精确匹配时,“=”区段的匹配优先级最高。 现在把“=”区段注释掉,接着实验
[root@hqidi vhosts]# sed -i '27,$s/^/#/' location
[root@hqidi vhosts]# cat !$
cat location
#1
location /abcd {
echo "现在匹配到的是 location /abcd";
}
#2
location ~* /abcd {
echo "现在匹配到的是 location ~* /abcd";
}
#3
location ~ /abcd {
echo "现在匹配到的是 location ~ /abcd";
}
#4
location ~ /abc {
echo "现在匹配到的是 location ~ /abc";
}
#5
location ^~ /abc {
echo "现在匹配到的是 location ^~ /abc";
}
#6
# location = /abcd {
#echo "现在匹配到的是 location = /abcd";
#}
[root@hqidi vhosts]# r /usr
/usr/local/nginx/sbin/nginx -s reload
当配置文件如上所示时:
这里,有同学就会有疑问了,这不对啊,这不应该是匹配到带有本地土著光环的"^~"段吗?原来,他的优先级虽然高于正则匹配,但低于空前缀(location /abcd)的精确匹配,当我们请求https://hqidi.com/abcd 时,先会被"location /abcd"匹配上,前面说过,仅仅字符串匹配上,它还是不死心的,还会去按配置文件中出现的顺序进行正则匹配。为了验证这个说法,我们把第二和第三区段换个位置:
#1
location /abcd {
echo "现在匹配到的是 location /abcd";
}
#3
location ~ /abcd {
echo "现在匹配到的是 location ~ /abcd";
}
#2
location ~* /abcd {
echo "现在匹配到的是 location ~* /abcd";
}
#4
location ~ /abc {
echo "现在匹配到的是 location ~ /abc";
}
#5
location ^~ /abc {
echo "现在匹配到的是 location ^~ /abc";
}
当配置文件如上所示时:
剔除干扰项,再次验证:
#1
# location /abcd {
#echo "现在匹配到的是 location /abcd";
#}
#3
location ~ /abcd {
echo "现在匹配到的是 location ~ /abcd";
}
#2
location ~* /abcd {
echo "现在匹配到的是 location ~* /abcd";
}
#4
location ~ /abc {
echo "现在匹配到的是 location ~ /abc";
}
#5
location ^~ /abc {
echo "现在匹配到的是 location ^~ /abc";
}
当配置文件如上所示时:
可以看出土著光环生效了。 这个"^~",一般用于控制静态文件: location ^~ /static/ { root /webroot/static/; } 如果你要强行用于动态文件:
location ~ .*.(php|php5)?$
{
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi.conf;
}
location ^~ /test/ { #因为^~的优先级比~高,当访问test/1.php,将被此段匹配到
# rules
}
结果就是php文件不会被解析。
接着实验
#1
location /abcd {
echo "现在匹配到的是 location /abcd";
}
#3
location ~ /abcd {
echo "现在匹配到的是 location ~ /abcd";
}
#2
location ~* /abcd {
echo "现在匹配到的是 location ~* /abcd";
}
#4
location ~ /abc {
echo "现在匹配到的是 location ~ /abc";
}
#5
# location ^~ /abc {
#echo "现在匹配到的是 location ^~ /abc";
#}
当配置文件如上所示时:
客户端请求https://hqidi.com/abcd的时候,"location /abcd"这个区段其实先被规则匹配到,不过规则查找并没有停止,继续去查找有没有能匹配上的正则,如果有,就使用该正则匹配,并停止正则检索。 匹配优先级验证完毕,最后看一个最长匹配是什么鬼,最长匹配在女生视角很好理解,她们总是喜欢长的。。。最长匹配其实很简单,就是看起来最像的优先匹配。
location ^~ /images/ {
echo "现在匹配到的是^~ /images/";
}
location /images/1/ {
echo "现在匹配到的是/images/1/";
}
当配置文件如上所示时:
最后,希望看完的你没晕。。
本文转载自笛声的Nginx的location规则迷之匹配
- Linux进程间通信(三) - 信号
- 我的WCF之旅(7):面向服务架构(SOA)和面向对象编程(OOP)的结合——如何实现Service Contract的继承
- Linux进程间通信(IPC)机制总览
- 负载均衡 - 综述
- 浅谈ASP.NET的Postback
- WCF版的PetShop之一:PetShop简介[提供源代码下载]
- 维吉尼亚密码及程序实现
- 迪菲-赫尔曼密钥交换
- 分布式系统组件之配置中心
- github 提交报403 forbidden的错误解决
- Apache thrift - 使用,内部实现及构建一个可扩展的RPC框架
- redis主从集群搭建及容灾部署(哨兵sentinel)
- 浅谈ASP.NET的Postback
- redis配置详解(中英文)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Loki和Fluentd的那点事儿
- 恕我直言你可能真的不会java第9篇-元素的匹配与查找
- 恕我直言你可能真的不会java第8篇-函数式接口
- 突破 DockerHub 限制,全镜像加速服务
- 恕我直言你可能真的不会java第7篇:像使用SQL一样排序集合
- K8S 生态周报| KIND v0.9 发布带来众多更新
- oracle 数据回滚,恢复误删的数据,闪回表功能的使用
- C语言 | 关于结构体内存对齐,看这篇就够了
- Python 图像处理篇-利用opencv库展示本地图片实例演示
- Python 图像处理篇-利用opencv库和numpy库读取包含中文路径下的本地图片实例演示
- 从头创建您自己的vue.js——第2部分(虚拟DOM基础)
- Manage Jenkins报错:"依赖错误: 部分插件由于缺少依赖无法加载...",解决办法
- 从头创建您自己的vuei .js——第3部分(构建VDOM)
- adb 模拟上下左右滑动,示例演示
- python 技术篇-pythoncom.PumpMessag()关闭、杀死它的进程,pythoncom.PumpMessag()运行卡住解决办法