
现象:主题明明有 404 页,访客看到的却是 nginx 的默认页
WordPress 主题通常会渲染一个像样的 404 页面(带导航、搜索框、"返回首页")。但我这个站上,故意访问一个不存在的地址时,返回的是 nginx 那个极简的默认 404 页。
量一下就很明显:
curl -s -o /dev/null -w '%{http_code} %{size_download} B\n' https://www.example.com/不存在的地址
我这边实测:404 / 146 B。而主题渲染出来的 404 页是三万多字节(写这篇时实测 35672 B,它会随页面内容浮动)。差了 200 多倍——说明主题的页面根本没被送到浏览器。
一、原因:fastcgi_intercept_errors on 加一条指向不存在文件的 error_page
链条是这样的:
- 全局
nginx.conf里开了fastcgi_intercept_errors on; - 站点 vhost 里有一行
error_page 404 /404.html; - 但站点根目录下并没有
404.html这个文件
于是当 WordPress(PHP)返回 404 时:
fastcgi_intercept_errors on让 nginx 接管 PHP 返回的错误码,用自己的错误页;- 它去找
/404.html,没找到; - 最后回退到 nginx 内置的 146 B 默认页。
结果:PHP 那边辛苦渲染的那三万多字节的主题 404 页,被整体替换掉了。
判断方法:看响应里有没有 WordPress 的特征。
curl -sD - -o /dev/null https://www.example.com/不存在的地址 | grep -iE 'HTTP/|x-powered|link|set-cookie'
如果只有 nginx 的头、没有任何 WordPress 痕迹,就说明请求的结果被 nginx 换掉了。
二、修复:让 PHP 的 404 原样透传
在站点级配置里加一行(只影响本站):
fastcgi_intercept_errors off;
这样 PHP 返回什么状态码和页面,nginx 就原样送给浏览器。
三、代价必须知道
关掉它之后,PHP 的 5xx 错误页也会原样透传——也就是说,如果 PHP 出错,用户可能看到白页或者报错内容,而不是 nginx 友好的错误页。
这是可以接受的交换:主题的 404 页是有设计、有导航的;PHP 5xx 本来就不该出现,出现时能看到真实报错反而有利于排障。 如果你的站点更在意"错误页要好看",可以换个思路:真的在站点根目录放一个 404.html,让 error_page 有东西可指。
另外注意:nginx 自身产生的静态 404(比如图片不存在)仍然会走 error_page,这条修改只影响 FastCGI(PHP)返回的错误。
四、排序问题
fastcgi_intercept_errors off; 是纯 server 指令,不含 rewrite,所以它不像那些带 if 的规则会被 break 干扰。但仍建议把它放到静态缓存规则之前的独立文件里,保持"先安全、后缓存"的顺序,便于日后维护。
五、验证
# 内容长度应该回到主题渲染的量级(几 KB 到几十 KB)
curl -s -o /dev/null -w '%{http_code} %{size_download} B\n' https://www.example.com/不存在的地址
# 页面里应能看到主题的导航/搜索等元素
curl -s https://www.example.com/不存在的地址 | grep -c 'site-navbar|search'
六、回滚
删掉那一行(或整个独立配置文件)→ nginx -t && nginx -s reload。回滚后立刻恢复成 nginx 默认页。
一句话总结:fastcgi_intercept_errors on 加上一个指向不存在文件的 error_page,会让主题精心渲染的 404 页被 nginx 的默认页静默替换。加一行 fastcgi_intercept_errors off; 就能让 PHP 的响应原样透传——代价是 PHP 5xx 也会露出真实内容。

评论 (0)