阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

Nginx配置中location匹配规则详解

514次阅读
没有评论

共计 11132 个字符,预计需要花费 28 分钟才能阅读完成。

Nginx 的语法形式是:location [=|~|~*|^~|@] /uri/ {…},意思是可以以“=”或“~*”或“~”或“^~”或“@”符号为前缀,当然也可以没有前缀(因为 [A] 是表示可选的 A;A|B 表示 A 和 B 选一个),紧接着是 /uri/,再接着是{…} 指令块,整个意思是对于满足这样条件的 /uri/ 适用指令块 {…} 的指令。

上述各种 location 可分两大类,分别是:“普通 location”,官方英文说法是 location using   literal strings 和“正则 location”,英文说法是 location using regular expressions。其中“普通 location”是以“=”或“^~”为前缀或者没有任何前缀的 /uri/;“正则 location”是以“~”或“~*”为前缀的 /uri/ 

那么,当我们在一个 server 上下文编写了多个 location 的时候,Nginx 对于一个 HTTP 请求,是如何匹配到一个 location 做处理呢?用一句话简单概括 Nginx 的 location 匹配规则是:“正则 location”让步 “普通 location”的严格精确匹配结果;但 覆盖“普通 location”的最大前缀匹配结果。理解这句话,我想通过下面的实例来说明。

#1 先普通 location,再正则 location

周边不少童鞋告诉我,nginx 是“先匹配正则 location 再匹配普通 location”,其实这是一个误区,nginx 其实是“先匹配普通 location,再匹配正则 location”,但是普通 location 的匹配结果又分两种:一种是“严格精确匹配”,官方英文说法是“exact match”;另一种是“最大前缀匹配”,官方英文说法是“Literal strings match the beginning portion of the query – the most specific match will be used.”。我们做个实验:

例题 1:假设 nginx 的配置如下

server {

       listen       9090;

       server_name  localhost;

                  location / {

           root   html;

           index  index.html index.htm;

           deny all;

       }

       location ~ \.html$ {

           allow all;

       }

}

附录 nginx 的目录结构是:nginx->html->index.html

上述配置的意思是:location / {… deny all;} 普通 location 以“/”开始的 URI 请求(注意任何 HTTP 请求都必然以“/”开始,所以“/”的意思是所有的请求都能被匹配上),都拒绝访问;location ~\.html$ {allow all;} 正则 location 以 .html 结尾的 URI 请求,都允许访问。

测试结果:

[root@web108 ~]# curl http://localhost:9090/

<html>

<head><title>403 Forbidden</title></head>

<body bgcolor=”white”>

<center><h1>403 Forbidden</h1></center>

<hr><center>nginx/1.1.0</center>

</body>

</html>

[root@web108 ~]# curl http://localhost:9090/index.html

<html>

<head>

<title>Welcome to nginx!</title>

</head>

<body bgcolor=”white”text=”black”>

<center><h1>Welcome to nginx!</h1></center>

</body>

</html>

[root@web108 ~]# curl http://localhost:9090/index_notfound.html

<html>

<head><title>404 Not Found</title></head>

<body bgcolor=”white”>

<center><h1>404 Not Found</h1></center>

<hr><center>nginx/1.1.0</center>

</body>

</html>

[root@web108 ~]#

测试结果如下:

URI 请求HTTP 响应
curl http://localhost:9090/403 Forbidden
curl http://localhost:9090/index.htmlWelcome to nginx!
curl http://localhost:9090/index_notfound.html404 Not Found

curl http://localhost:9090/ 的结果是“403 Forbidden”,说明被匹配到“location / {..deny all;}”了,原因很简单 HTTP 请求 GET / 被“严格精确”匹配到了普通 location / {},则会停止搜索正则 location;

curl http://localhost:9090/index.html 结果是“Welcome to nginx!”,说明没有被“location / {…deny all;}”匹配,否则会 403 Forbidden,但 /index.html 的确也是以“/”开头的,只不过此时的普通 location / 的匹配结果是“最大前缀”匹配,所以 Nginx 会继续搜索正则 location,location ~ \.html$ 表达了以 .html 结尾的都 allow all; 于是接着就访问到了实际存在的 index.html 页面。

curl http://localhost:9090/index_notfound.html   同样的道理先匹配 location / {},但属于“普通 location 的最大前缀匹配”,于是后面被“正则 location”location ~ \.html$ {} 覆盖了,最终 allow all;但的确目录下不存在 index_notfound.html 页面,于是 404 Not Found。

如果此时我们访问 http://localhost:9090/index.txt 会是什么结果呢?显然是 deny all;因为先匹配上了 location / {..deny all;} 尽管属于“普通 location”的最大前缀匹配结果,继续搜索正则 location,但是 /index.txt 不是以 .html 结尾的,正则 location 失败,最终采纳普通 location 的最大前缀匹配结果,于是 deny all 了。

[root@web108 ~]# curl http://localhost:9090/index.txt

<html>

<head><title>403 Forbidden</title></head>

<body bgcolor=”white”>

<center><h1>403 Forbidden</h1></center>

<hr><center>nginx/1.1.0</center>

</body>

</html>

[root@web108 ~]#

#2 普通 location 的“隐式”严格匹配

例题 2:我们在例题 1 的基础上增加精确配置

server {

       listen       9090;

       server_name  localhost;

                  location /exact/match.html {

           allow all;

       }

                  location / {

           root   html;

           index  index.html index.htm;

           deny all;

       }

       location ~ \.html$ {

           allow all;

       }

}

测试请求:

[root@web108 ~]# curl http://localhost:9090/exact/match.html

<html>

<head><title>404 Not Found</title></head>

<body bgcolor=”white”>

<center><h1>404 Not Found</h1></center>

<hr><center>nginx/1.1.0</center>

</body>

</html>

[root@web108 ~]#

结果进一步验证了“普通 location”的“严格精确”匹配会终止对正则 location 的搜索。这里我们小结下“普通 location”与“正则 location”的匹配规则:先匹配普通 location,再匹配正则 location,但是如果普通 location 的匹配结果恰好是“严格精确(exact match)”的,则 nginx 不再尝试后面的正则 location;如果普通 location 的匹配结果是“最大前缀”,则正则 location 的匹配覆盖普通 location 的匹配。也就是前面说的“正则 location 让步普通 location 的严格精确匹配结果,但覆盖普通 location 的最大前缀匹配结果”。

#3 普通 location 的“显式”严格匹配和“^~”前缀

上面我们演示的普通 location 都是不加任何前缀的,其实普通 location 也可以加前缀:“^~”和“=”。其中“^~”的意思是“非正则,不需要继续正则匹配”,也就是通常我们的普通 location,还会继续搜索正则 location(恰好严格精确匹配除外),但是 nginx 很人性化允许配置人员告诉 nginx 某条普通 location,无论最大前缀匹配,还是严格精确匹配都终止继续搜索正则 location;而“=”则表达的是普通 location 不允许“最大前缀”匹配结果,必须严格等于,严格精确匹配

例题 3:“^~”前缀的使用

server {

       listen       9090;

       server_name  localhost;

                  location /exact/match.html {

           allow all;

       }

                 location ^~ / {

           root   html;

           index  index.html index.htm;

           deny all;

       }

       location ~ \.html$ {

           allow all;

       }

}

把例题 2 中的 location / {} 修改成 location ^~ / {},再看看测试结果:

URI 请求修改前修改后
curl http://localhost:9090/403 Forbidden403 Forbidden
curl http://localhost:9090/index.htmlWelcome to nginx!403 Forbidden
curl http://localhost:9090/index_notfound.html404 Not Found403 Forbidden
curl http://localhost:9090/exact/match.html404 Not Found404 Not Found

除了 GET /exact/match.html 是 404 Not Found,其余都是 403 Forbidden,原因很简单所有请求都是以“/”开头,所以所有请求都能匹配上“/”普通 location,但普通 location 的匹配原则是“最大前缀”,所以只有 /exact/match.html 匹配到 location /exact/match.html {allow all;},其余都 location ^~ / {deny all;} 并终止正则搜索。

例题 4:“=”前缀的使用

server {

       listen       9090;

       server_name  localhost;

                  location /exact/match.html {

           allow all;

       }

                 location = / {

           root   html;

           index  index.html index.htm;

           deny all;

       }

       location ~ \.html$ {

           allow all;

       }

}

例题 4 相对例题 2 把 location / {} 修改成了 location = / {},再次测试结果:

URI 请求修改前修改后
curl http://localhost:9090/403 Forbidden403 Forbidden
curl http://localhost:9090/index.htmlWelcome to nginx!Welcome to nginx!
curl http://localhost:9090/index_notfound.html404 Not Found404 Not Found
curl http://localhost:9090/exact/match.html404 Not Found404 Not Found
curl http://localhost:9090/test.jsp403 Forbidden404 Not Found

最能说明问题的测试是 GET /test.jsp,实际上 /test.jsp 没有匹配正则 location(location ~\.html$),也没有匹配 location = / {},如果按照 location / {} 的话,会“最大前缀”匹配到普通 location / {},结果是 deny all。

#4 正则 location 与编辑顺序

location 的指令与编辑顺序无关,这句话不全对。对于普通 location 指令,匹配规则是:最大前缀匹配(与顺序无关),如果恰好是严格精确匹配结果或者加有前缀“^~”或“=”(符号“=”只能严格匹配,不能前缀匹配),则停止搜索正则 location;但对于正则 location 的匹配规则是:按编辑顺序逐个匹配(与顺序有关),只要匹配上,就立即停止后面的搜索。

配置 3.1

server {

       listen       9090;

       server_name  localhost;

       location ~ \.html$ {

           allow all; 

       } 

       location ~ ^/prefix/.*\.html$ {

           deny all; 

       } 

}

配置 3.2

server {

       listen       9090;

       server_name  localhost;

     

       location ~ ^/prefix/.*\.html$ {

           deny all; 

       } 

                 

                  location ~ \.html$ {

           allow all; 

       } 

}

测试结果:

URI 请求配置 3.1配置 3.2
curl http://localhost:9090/regextest.html404 Not Found404 Not Found
curl http://localhost:9090/prefix/regextest.html404 Not Found403 Forbidden

解释:

Location ~ ^/prefix/.*\.html$ {deny all;} 表示正则 location 对于以 /prefix/ 开头,.html 结尾的所有 URI 请求,都拒绝访问;location ~\.html${allow all;} 表示正则 location 对于以 .html 结尾的 URI 请求,都允许访问。实际上,prefix 的是 ~\.html$ 的子集。

在“配置 3.1”下,两个请求都匹配上 location ~\.html$ {allow all;},并且停止后面的搜索,于是都允许访问,404 Not Found;在“配置 3.2”下,/regextest.html 无法匹配 prefix,于是继续搜索 ~\.html$,允许访问,于是 404 Not Found;然而 /prefix/regextest.html 匹配到 prefix,于是 deny all,403 Forbidden。

配置 3.3

server {

       listen       9090;

       server_name  localhost;

       location  /prefix/ {

               deny all; 

       } 

         

       location  /prefix/mid/ {

               allow all; 

       } 

}

配置 3.4

server {

       listen       9090;

       server_name  localhost;

     

       location  /prefix/mid/ {

               allow all; 

       } 

                  location  /prefix/ {

               deny all; 

       } 

}

测试结果:

URI 请求配置 3.1配置 3.2
curl http://localhost:9090/prefix/t.html403 Forbidden403 Forbidden
curl http://localhost:9090/prefix/mid/t.html404 Not Found404 Not Found

测试结果表明:普通 location 的匹配规则是“最大前缀”匹配,而且与编辑顺序无关。

#5“@”前缀 Named Location 使用

REFER:  http://wiki.nginx.org/HttpCoreModule#error_page

假设配置如下:

server {

       listen       9090;

       server_name  localhost;

        location  / {

           root   html;

           index  index.html index.htm;

           allow all;

       }

       #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 指令能捕获它)。

测试一:

[root@web108 ~]# curl http://localhost:9090/nofound.html -i

HTTP/1.1 302 Found

Server: nginx/1.1.0

Date: Sat, 06 Aug 2011 08:17:21 GMT

Content-Type: text/html; charset=iso-8859-1

Location: http://localhost:9090/search/error.html

Connection: keep-alive

Cache-Control: max-age=86400

Expires: Sun, 07 Aug 2011 08:17:21 GMT

Content-Length: 222

<!DOCTYPE HTML PUBLIC“-//IETF//DTD HTML 2.0//EN”>

<html><head>

<title>302 Found</title>

</head><body>

<h1>Found</h1>

<p>The document has moved <a href=”http://www.baidu.com/search/error.html”>here</a>.</p>

</body></html>

[root@web108 ~]#

当我们 GET /nofound.html 发送给本 nginx,nginx 找不到对应的页面,于是 error_page 404 = @fallback,请求被代理到 http://www.baidu.com,于是 nginx 给 http://www.baidu.com 发送了 GET /nofound.html,但 /nofound.html 页面在百度也不存在,百度 302 跳转到错误页。

直接访问 http://www.baidu.com/nofound.html 结果:

[root@web108 ~]# curl http://www.baidu.com/nofound.html -i

HTTP/1.1 302 Found

Date: Sat, 06 Aug 2011 08:20:05 GMT

Server: Apache

Location: http://www.baidu.com/search/error.html

Cache-Control: max-age=86400

Expires: Sun, 07 Aug 2011 08:20:05 GMT

Content-Length: 222

Connection: Keep-Alive

Content-Type: text/html; charset=iso-8859-1

<!DOCTYPE HTML PUBLIC“-//IETF//DTD HTML 2.0//EN”>

<html><head>

<title>302 Found</title>

</head><body>

<h1>Found</h1>

<p>The document has moved <a href=”http://www.baidu.com/search/error.html”>here</a>.</p>

</body></html>

[root@web108 ~]#

测试二:访问一个 nginx 不存在,但 baidu 存在的页面

[root@web108 ~]# curl http://www.baidu.com/duty/ -i

HTTP/1.1 200 OK

Date: Sat, 06 Aug 2011 08:21:56 GMT

Server: Apache

P3P: CP=”OTI DSP COR IVA OUR IND COM”

P3P: CP=”OTI DSP COR IVA OUR IND COM”

Set-Cookie: BAIDUID=5C5D2B2FD083737A0C88CA7075A6601A:FG=1; expires=Sun, 05-Aug-12 08:21:56 GMT; max-age=31536000; path=/; domain=.baidu.com; version=1

Set-Cookie: BAIDUID=5C5D2B2FD083737A2337F78F909CCB90:FG=1; expires=Sun, 05-Aug-12 08:21:56 GMT; max-age=31536000; path=/; domain=.baidu.com; version=1

Last-Modified: Wed, 05 Jan 2011 06:44:53 GMT

ETag:“d66-49913b8efe340″

Accept-Ranges: bytes

Content-Length: 3430

Cache-Control: max-age=86400

Expires: Sun, 07 Aug 2011 08:21:56 GMT

Vary: Accept-Encoding,User-Agent

Connection: Keep-Alive

Content-Type: text/html

<!DOCTYPE HTML PUBLIC“-//W3C//DTD HTML 4.01 Transitional//EN”

“http://www.w3.org/TR/html4/loose.dtd”>

。。。。

</body>

</html>

显示,的确百度这个页面是存在的。

[root@web108 ~]# curl http://localhost:9090/duty/ -i

HTTP/1.1 200 OK

Server: nginx/1.1.0

Date: Sat, 06 Aug 2011 08:23:23 GMT

Content-Type: text/html

Connection: keep-alive

P3P: CP=”OTI DSP COR IVA OUR IND COM”

P3P: CP=”OTI DSP COR IVA OUR IND COM”

Set-Cookie: BAIDUID=8FEF0A3A2C31D277DCB4CC5F80B7F457:FG=1; expires=Sun, 05-Aug-12 08:23:23 GMT; max-age=31536000; path=/; domain=.baidu.com; version=1

Set-Cookie: BAIDUID=8FEF0A3A2C31D277B1F87691AFFD7440:FG=1; expires=Sun, 05-Aug-12 08:23:23 GMT; max-age=31536000; path=/; domain=.baidu.com; version=1

Last-Modified: Wed, 05 Jan 2011 06:44:53 GMT

ETag:“d66-49913b8efe340″

Accept-Ranges: bytes

Content-Length: 3430

Cache-Control: max-age=86400

Expires: Sun, 07 Aug 2011 08:23:23 GMT

Vary: Accept-Encoding,User-Agent

<!DOCTYPE HTML PUBLIC“-//W3C//DTD HTML 4.01 Transitional//EN”

“http://www.w3.org/TR/html4/loose.dtd”>

<html>

。。。

</body>

</html>

当 curl http://localhost:9090/duty/ -i 时,nginx 没找到对应的页面,于是 error_page = @fallback,把请求代理到 baidu.com。注意这里的 error_page = @fallback 不是靠重定向实现的,而是所说的“internally redirected(forward)”。

正文完
星哥玩云-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2022-01-21发表,共计11132字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中

星哥玩云

星哥玩云
星哥玩云
分享互联网知识
用户数
4
文章数
19351
评论数
4
阅读量
7993413
文章搜索
热门文章
星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛 NAS-6:抖音视频同步工具,视频下载自动下载保存 前言 各位玩 NAS 的朋友好,我是星哥!...
星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛 NAS-3:安装飞牛 NAS 后的很有必要的操作 前言 如果你已经有了飞牛 NAS 系统,之前...
我把用了20年的360安全卫士卸载了

我把用了20年的360安全卫士卸载了

我把用了 20 年的 360 安全卫士卸载了 是的,正如标题你看到的。 原因 偷摸安装自家的软件 莫名其妙安装...
再见zabbix!轻量级自建服务器监控神器在Linux 的完整部署指南

再见zabbix!轻量级自建服务器监控神器在Linux 的完整部署指南

再见 zabbix!轻量级自建服务器监控神器在 Linux 的完整部署指南 在日常运维中,服务器监控是绕不开的...
飞牛NAS中安装Navidrome音乐文件中文标签乱码问题解决、安装FntermX终端

飞牛NAS中安装Navidrome音乐文件中文标签乱码问题解决、安装FntermX终端

飞牛 NAS 中安装 Navidrome 音乐文件中文标签乱码问题解决、安装 FntermX 终端 问题背景 ...
阿里云CDN
阿里云CDN-提高用户访问的响应速度和成功率
随机文章
升级自动部署更新SSL证书系统、申请godaddy的APIKEY

升级自动部署更新SSL证书系统、申请godaddy的APIKEY

升级自动部署更新 SSL 证书系统、申请 godaddy 的 APIKEY 公司之前花钱购买的 ssl 证书快...
浏览器自动化工具!开源 AI 浏览器助手让你效率翻倍

浏览器自动化工具!开源 AI 浏览器助手让你效率翻倍

浏览器自动化工具!开源 AI 浏览器助手让你效率翻倍 前言 在 AI 自动化快速发展的当下,浏览器早已不再只是...
星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛 NAS-6:抖音视频同步工具,视频下载自动下载保存 前言 各位玩 NAS 的朋友好,我是星哥!...
一句话生成拓扑图!AI+Draw.io 封神开源组合,工具让你的效率爆炸

一句话生成拓扑图!AI+Draw.io 封神开源组合,工具让你的效率爆炸

一句话生成拓扑图!AI+Draw.io 封神开源组合,工具让你的效率爆炸 前言 作为天天跟架构图、拓扑图死磕的...
手把手教你,购买云服务器并且安装宝塔面板

手把手教你,购买云服务器并且安装宝塔面板

手把手教你,购买云服务器并且安装宝塔面板 前言 大家好,我是星哥。星哥发现很多新手刚接触服务器时,都会被“选购...

免费图片视频管理工具让灵感库告别混乱

一言一句话
-「
手气不错
星哥带你玩飞牛NAS硬件03:五盘位+N5105+双网口的成品NAS值得入手吗

星哥带你玩飞牛NAS硬件03:五盘位+N5105+双网口的成品NAS值得入手吗

星哥带你玩飞牛 NAS 硬件 03:五盘位 +N5105+ 双网口的成品 NAS 值得入手吗 前言 大家好,我...
自己手撸一个AI智能体—跟创业大佬对话

自己手撸一个AI智能体—跟创业大佬对话

自己手撸一个 AI 智能体 — 跟创业大佬对话 前言 智能体(Agent)已经成为创业者和技术人绕...
如何安装2026年最强个人助理ClawdBot、完整安装教程

如何安装2026年最强个人助理ClawdBot、完整安装教程

如何安装 2026 年最强个人助理 ClawdBot、完整安装教程 一、前言 学不完,根本学不完!近期,一款名...
Prometheus:监控系统的部署与指标收集

Prometheus:监控系统的部署与指标收集

Prometheus:监控系统的部署与指标收集 在云原生体系中,Prometheus 已成为最主流的监控与报警...
星哥带你玩飞牛NAS-14:解锁公网自由!Lucky功能工具安装使用保姆级教程

星哥带你玩飞牛NAS-14:解锁公网自由!Lucky功能工具安装使用保姆级教程

星哥带你玩飞牛 NAS-14:解锁公网自由!Lucky 功能工具安装使用保姆级教程 作为 NAS 玩家,咱们最...