很多站长写 Nginx 配置,看到一堆 location 就头大:有的前面带 =,有的带 ^~,有的带 ~,到底什么区别?写错了规则,网站要么 404,要么配置完全不生效。location 是 Nginx 里出现频率最高、也最容易写错的配置块。这篇文章把匹配规则、优先级、实战写法一次讲清。
一、location 是干什么的
location 用来匹配请求的 URL 路径,并指定这一部分用什么规则处理(静态文件、转发后端、拒绝访问等)。一个请求过来,Nginx 会在所有 location 里挑一个最合适的来执行。
location / {
root /www/html;
}
二、四种匹配符号的区别
Nginx 的 location 匹配分两大类:前缀匹配和正则匹配,写法如下:
1. 精确匹配 =
location = / {
# 只匹配请求路径正好是 / 的
}
location = /login.html {
# 只匹配 /login.html,不匹配 /login.html/xxx
}
2. 普通前缀匹配(无符号)
location /images/ {
# 匹配以 /images/ 开头的
}
3. 前缀匹配且不再往下查正则 ^~
location ^~ /static/ {
# 匹配 /static/ 开头,命中后不再尝试正则
}
4. 正则匹配 ~(区分大小写)和 ~*(不区分)
location ~ \.(gif|jpg|png)$ {
# 以 .gif/.jpg/.png 结尾,区分大小写
}
location ~* \.(css|js)$ {
# 以 .css/.js 结尾,不区分大小写
}
三、优先级:记住这张表
Nginx 匹配规则总结为一句口诀:精确 > ^~ > 正则 > 普通前缀 > 默认(/)。
匹配顺序:
- 先把所有普通前缀(
=、无符号、^~)都匹配一遍,找到最长的那个 - 如果最长的是
^~,直接用它,不再查正则 - 否则继续按配置文件里的先后顺序试正则(
~/~*),一旦命中就停 - 没有正则命中,就用步骤 1 找到的最长前缀
优先级示例:
location = / { ... } # 1 精确最高
location ^~ /images/ { ... } # 2 ^~ 次之
location ~ \.php$ { ... } # 3 正则
location /images/ { ... } # 4 普通前缀(与 ^~ 冲突时 ^~ 赢)
location / { ... } # 5 兜底
请求 /images/logo.png 会命中 ^~ /images/(因为 ^~ 不再查正则);请求 /index.php 会命中正则 ~ \.php$。
四、经典实战配置
1. PHP 站点(最标准写法):
server {
listen 80;
server_name example.com;
# 静态资源:命中就直接用文件,不交给 PHP
location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff2?)$ {
expires 30d;
access_log off;
}
# PHP 请求交给 php-fpm
location ~ \.php$ {
root /www/html;
fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location / {
root /www/html;
index index.php index.html;
}
}
2. 精确匹配放行/拒绝:
# 后台入口只允许白名单
location = /admin {
allow 1.2.3.4;
deny all;
}
3. 图片防盗链 + 匹配:
location ~* \.(gif|jpg|png|webp)$ {
valid_referers none blocked example.com *.example.com;
if ($invalid_referer) {
return 403;
}
}
4. 反向代理匹配:
location /api/ {
proxy_pass http://127.0.0.1:8080;
}
location ^~ /websocket/ {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
五、常见坑与排查
Q1:为什么我的正则 location 没生效?
正则只有在没有 ^~ 且没有被更长前缀先命中时才生效。常见错误:写了个长普通前缀 /images/,又写正则 ~ \.jpg$,但请求先命中了普通前缀(因为普通前缀找最长,然后才试正则)——正则其实还是会试。真正跳过正则的只有 ^~ 和 =。检查你是否把规则写成了 ^~。
Q2:location / 里的配置不生效?
location / 是兜底,只有其他所有规则都没命中时才用。别把核心逻辑都放这,优先用更具体的匹配。
Q3:~ 和 ~* 写反了大小写行为?
~ 区分大小写(\.php$ 不匹配 .PHP),~* 不区分。静态资源一般用 ~* 更稳。
Q4:改完配置不生效?
nginx -t 检查语法,nginx -s reload 平滑重载。注意 location 里的缩进不影响语法,但大括号别丢。
Q5:proxy_pass 结尾带不带 / 的区别?
带 / 表示替换前缀,不带 / 表示拼接完整路径,这是经典坑。要转发目录建议直接看本站 Nginx 反向代理教程里的详细说明。
六、如何测试自己的匹配
改完用 curl 打真实路径验证:
curl -I http://127.0.0.1/logo.png
curl -I http://127.0.0.1/index.php
配合 tail -f /var/log/nginx/access.log 看请求命中了哪个 location(日志里看不出 location,但能确认返回码和是否走了 PHP)。
总结
location 四种写法、三层优先级:= 精确 > ^~ 前缀(不查正则)> 正则(~ / ~*)> 普通前缀 / 兜底。写配置时记住:静态文件用正则 ~*,PHP 用 ~ \.php$,目录转发用普通前缀,需要跳过正则时用 ^~。多动手测试,配错了用 nginx -t 和 curl 就能定位。配合本站 Nginx 反向代理、缓存、HTTPS 等教程,Nginx 就基本玩明白了。
