⭐ 推荐:社区规则条款 V1.0

Nginx 伪静态规则写错导致 404 怎么排查?

域名注册
域名注册 版主归队站长新人站长 👑年卡会员
发布于 2026-10-14 16:16 ·0 浏览 ·3 回复
内容摘要

排查 Nginx 伪静态规则错误导致的 404,可先用 curl -i 区分 Nginx 还是后端返回,再查 error/access 日志并记录 $uri 与 $request_uri,最后检查 location 匹配优先级,定位未执行或

Nginx 伪静态规则写错导致 404 怎么排查?,本文转载自 GJ站长论坛,原文地址:https://www.gj0.com/thread-1963.html
转载请注明出处,版权归原作者所有。
—/ 5暂无评分
还没有评分,来打第一分吧

全部回复 3

chinaz
chinaz 归队站长新人站长 1楼 2026-10-14 16:21

定位到具体哪一行,最快的办法不是看日志猜,而是把每条 rewrite 临时改成 return 200 "rule-X"; 做二分标记——直接看哪条先执行、哪条根本没进。

具体做法:把 location / 里那串 rewrite 逐条前面插一句 return 200 "hit-rule-1\n";(记得改完 nginx -t && nginx -s reload),用 curl 打请求,返回哪个标记就说明前面几条都没命中、卡在这一条。定位到行后把标记删掉,再单独调那一条。这比在日志里分辨 $uri 变化要直观得多,尤其是规则超过三条的时候。

接着要区分 rewrite ... last 和 break:last 会把重写后的 URI 重新丢回 location 匹配一轮,你帖子第三步说的"被 ^~ 抢走"往往就是这么来的;break 则在本 location 内继续,不再重新匹配。伪静态到 index.php 这种场景,try_files $uri $uri/ /index.php?$query_string; 通常比手写 rewrite 更稳,也不容易出循环。

还有个高频坑:你改的可能是 /etc/nginx/conf.d/xxx.conf,但实际生效的是 sites-enabled 里的软链或另一份 include 顺序更靠前的配置。先 nginx -T | grep -n "rewrite" 把最终合并后的配置打出来对一遍,能省掉一半的"改了没效果"。

lqyyzz
lqyyzz 观望站长 #1508 2楼 2026-10-14 16:40
chinaz:定位到具体哪一行,最快的办法不是看日志猜,而是**把每条 rewrite 临时改成 `return 200 "rule-X";` 做二分标记**——直接看哪条先…

思路对,插 return 做二分定位确实比在 access.log 里盯 $uri 变化快,但有两个前提得先说清,不然容易得出反向结论。

一是 return 属于 rewrite 阶段指令,一旦命中就直接短路返回,后面的规则和 location ~ \.php$ 的转发全都不会执行——所以它只能回答"顺序上卡在哪条",不能证明这条规则本身写错了。定位到行之后必须把标记删掉原样复现一次,别拿带标记的结果当结论。二是如果连 hit-rule-1 都没打出来,说明请求压根没进这个 location,这时候别再往下加规则,直接回头查 server 块匹配。

想少改配置文件的话,补一句 rewrite_log on; 并让 error_log 开到 notice 级别,Nginx 会把每条 rewrite 的输入输出配对打出来,等价于自动版标记,而且不改变执行逻辑。break 和 last 的区别你说得也对,last 会重新走一轮 location 匹配,被 ^~ 抢走基本就是这个原因。

try_files 那段同意,补一点:最后那一段 /index.php?$query_string 是内部重定向,同样要重走 location 匹配,所以 location ~ \.php$ 必须存在且 fastcgi_pass 正确,否则结果是 404 而不是你预期的报错,排查时容易误判成 root 写错。

nginx -T 那招我再加一刀:输出里每条片段前都有 # configuration file xxx 注释行,直接 grep 文件名比 grep rewrite 更快锁定来源。还有一种更阴的情况是请求被别的 server 块的 default_server 接走了,用 curl -H "Host: 你的域名" http://127.0.0.1/... 排除 DNS 和 CDN 干扰。

最后提醒一句:nginx -s reload 如果配置有语法错,会直接失败并继续用旧配置跑,你会以为"改了没生效",所以每次务必先 nginx -t。

满月居于空
满月居于空 版主资深会员新人站长 👑年卡会员 #1510 3楼 2026-10-14 16:49
lqyyzz:思路对,插 `return` 做二分定位确实比在 access.log 里盯 `$uri` 变化快,但有两个前提得先说清,不然容易得出反向结论。 一是 `re…

补的这两条前提都在点上,尤其 return,它是 rewrite 阶段直接短路返回,命中即结束,后面的规则和 location ~ \.php$ 压根不执行,所以只能证明顺序卡在哪,证不了规则本身写没写错,拿带标记的结果反推容易得出相反结论。

如果想做二分又不改变执行路径,有个更干净的办法:在各个 location 里塞一句 add_header X-Debug-Rule "1" always;,然后看响应头命中哪个块。关键在 always,不带它的话 add_header 默认只在 200/301/302 这类状态码下输出,404 恰好不生效,等于把最该排查的场景全漏掉了。它不打断 try_files 和内部重定向,比 return 更适合拿来定位。

rewrite_log on; 也有个边界值得说:它只打印 rewrite 模块的输入输出配对,try_files 的决策和内部重定向不打。所以 try_files 那段我还是习惯在 log_format 里加 $request_filename,它是 root/alias 拼接后的最终文件路径,和 $uri 一对照,是目录写错还是规则写错立刻分家。