Nginx 作为当前最流行的 Web 服务器和反向代理服务器之一,其 location 指令的匹配规则是配置中最核心也最容易出错的部分。许多运维人员和开发者在配置 Nginx 时,常常因为对匹配优先级理解不清,导致请求被错误地路由到非预期的后端或静态资源目录。本文将系统性地梳理 location 的语法、匹配类型以及优先级顺序,并通过实例帮助读者彻底掌握这一知识点。
一、location 的基本语法
location 指令位于 server 块或 location 块内部,用于根据请求的 URI(统一资源标识符)来匹配不同的处理逻辑。其基本语法如下:
location [修饰符] 匹配模式 {
# 配置指令
}
其中,修饰符是可选的,匹配模式可以是字符串或正则表达式。修饰符决定了匹配的方式和优先级,是理解整个规则的关键。
二、location 的匹配类型
Nginx 的 location 匹配分为两大类:前缀匹配和正则匹配。具体来说,有以下几种修饰符:
1. 无修饰符(普通前缀匹配)
location /images/ {
root /var/www;
}
这是最常见的形式。Nginx 会将请求 URI 与 /images/ 进行前缀比较,如果 URI 以该字符串开头,则匹配成功。多个普通前缀匹配同时命中时,Nginx 会选择最长的那个。
2. = 精确匹配
location = /login {
proxy_pass http://backend;
}
= 表示精确匹配,只有当请求 URI 与匹配模式完全相等时才会命中。精确匹配的优先级最高,一旦命中,Nginx 将立即停止后续匹配。
3. ^~ 非正则前缀匹配(优先前缀匹配)
location ^~ /static/ {
root /var/www;
}
^~ 表示如果该前缀匹配成功,则不再尝试后续的正则匹配。它通常用于避免某个前缀路径被后面的正则规则“抢走”。注意,^~ 仍然属于前缀匹配,只是它一旦命中且为最长前缀,就会抑制正则匹配。
4. ~ 区分大小写的正则匹配
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
}
~ 表示使用正则表达式进行匹配,且区分大小写。正则匹配按照在配置文件中出现的顺序依次尝试,一旦某个正则匹配成功,就立即使用该 location,不再继续后面的正则匹配。
5. ~* 不区分大小写的正则匹配
location ~* \.(jpg|jpeg|png|gif)$ {
expires 30d;
}
~* 与 ~ 类似,但在匹配时不区分大小写。同样,一旦命中就停止后续正则匹配。
6. @ 命名 location
location @fallback {
proxy_pass http://backup;
}
@ 用于定义命名 location,它不能直接匹配请求 URI,只能在 error_page、try_files 等指令中通过名称引用,常用于内部重定向。
三、location 的优先级顺序
Nginx 在处理请求时,会按照以下顺序依次进行匹配:
- 精确匹配
=:如果找到完全相等的 location,立即使用,结束匹配。 - 前缀匹配:找出所有普通前缀匹配和
^~前缀匹配中最长的那个。- 如果最长匹配带有
^~修饰符,则直接使用该 location,不进行正则匹配。 - 如果最长匹配是普通前缀(无修饰符),则先记住它,继续进入正则匹配阶段。
- 如果最长匹配带有
- 正则匹配
~和~*:按照配置文件中出现的顺序,依次尝试正则表达式。一旦某个正则匹配成功,立即使用该 location,并放弃之前记住的普通前缀匹配。 - 如果所有正则都未匹配:则使用第 2 步中记住的最长普通前缀匹配。
- 如果没有任何前缀匹配:返回 404 错误,除非有默认的
location /。
可以用一句话概括:精确匹配 > ^~ 前缀匹配 > 正则匹配 > 普通前缀匹配。但要注意,正则匹配的优先级虽然高于普通前缀,却低于 ^~,且正则之间按顺序先到先得。
四、实例分析
假设有如下配置:
server {
listen 80;
server_name example.com;
location = / {
return 200 "Exact root\n";
}
location / {
return 200 "Prefix root\n";
}
location ^~ /images/ {
return 200 "Images\n";
}
location ~ \.php$ {
return 200 "PHP\n";
}
location ~* \.(jpg|png)$ {
return 200 "Image regex\n";
}
location /images/logo.jpg {
return 200 "Specific image\n";
}
}
我们逐一分析不同请求的匹配结果:
- 请求
/:精确匹配location = /,返回 "Exact root"。 - 请求
/index.html:普通前缀/匹配,但正则都不匹配,最终使用location /,返回 "Prefix root"。 - 请求
/images/photo.png:前缀匹配中,/images/带有^~,且是最长前缀,因此直接使用它,返回 "Images"。注意,虽然~* \.(jpg|png)$也能匹配,但被^~抑制。 - 请求
/images/logo.jpg:前缀匹配中,/images/logo.jpg是最长普通前缀,但正则~* \.(jpg|png)$会先被尝试并匹配成功,因此返回 "Image regex"。这说明普通前缀再长,也敌不过正则。 - 请求
/upload/photo.jpg:前缀/匹配,正则~* \.(jpg|png)$匹配成功,返回 "Image regex"。 - 请求
/api/test.php:前缀/匹配,正则~ \.php$匹配成功,返回 "PHP"。
五、常见误区与最佳实践
误区一:认为普通前缀越长优先级越高。 实际上,普通前缀再长,只要有一个正则匹配成功,就会覆盖它。只有 ^~ 才能阻止正则匹配。
误区二:认为正则匹配会按“最精确”原则选择。 正则匹配是按配置文件中的顺序,先到先得。因此,将更具体的正则写在前面非常重要。
最佳实践:
- 对于静态资源目录,使用
^~前缀匹配,避免被正则规则意外拦截。 - 对于 PHP 等动态脚本,使用
~ \.php$正则,并注意将其放在其他正则之前(如果存在冲突)。 - 精确匹配
=用于根路径或特定 API 端点,性能最高。 - 使用
nginx -T测试配置,并通过curl -I验证实际匹配结果。
六、总结
Nginx 的 location 匹配规则看似复杂,但只要记住“精确 > ^~ > 正则(按顺序) > 普通前缀(最长)”这一优先级链,就能在绝大多数场景下做出正确配置。理解这些规则不仅能避免请求被错误路由,还能提升服务器的安全性和性能。建议在实际项目中多写测试用例,观察 Nginx 的匹配行为,从而真正做到心中有数。
未经允许不得转载:任鹏个人博客 » 深入理解 Nginx location 匹配规则与优先级


朋友圈点赞图在线生成源码