必须开启 fastcgi_intercept_errors on 并配合 error_page 404 = /404.html,确保 PHP 返回404时Nginx接管并返回自定义页面;同时需避免伪静态规则拦截错误页路径,验证PHP确实输出404状态码。

在 ThinkPHP 等框架配合 Nginx 伪静态运行时,用户访问不存在的路由(如 /user/999)本应由 PHP 框架返回 404 页面,但常出现 Nginx 直接抛出默认 404、或空白页、甚至暴露 PHP 错误信息。根本原因之一是 fastcgi_intercept_errors 未启用或配置不匹配——它决定了 Nginx 是否“接管” PHP 返回的 4xx/5xx 状态码并触发自定义错误页。
必须开启 fastcgi_intercept_errors
该指令默认为 off,即 PHP 返回 404 时,Nginx 不拦截,直接透传给浏览器(可能显示简陋的 Nginx 默认页,或被浏览器美化成空白)。要让 error_page 404 = /404.html 生效,必须显式开启:
- 推荐加在
server块内(作用范围明确,避免全局干扰):fastcgi_intercept_errors on; - 不要只写在
http块——若某站点不需要自定义错误页,容易误生效;也不建议写在location ~ \.php$内部——部分旧版 Nginx 不支持嵌套生效 - 确认它与
error_page在同一作用域(同个server),否则不联动
error_page 必须带等号且路径可访问
伪静态场景下,常见错误是写成 error_page 404 /404.html(无等号),这会让 Nginx 尝试内部重定向到 /404.html,但若该路径本身也走伪静态规则(如被 try_files $uri $uri/ /index.php?$query_string 拦截),就会循环或失败。
- 正确写法是带
=:error_page 404 = /404.html;—— 表示直接返回该文件内容,不触发新请求 - 确保
/404.html文件真实存在,且位于网站根目录(如/www/wwwroot/example.com/404.html),Nginx 有读取权限(644) - 文件大小需 ≥512 字节,否则 IE/Edge 可能强制替换为浏览器内置 404 页
避开伪静态规则对错误页的拦截
ThinkPHP 常用的伪静态配置含 try_files 或 rewrite,它们会优先匹配所有请求。若 location / 块中已有 try_files $uri $uri/ /index.php?$query_string;,那么当请求 /404.html 时,Nginx 会先检查文件是否存在;若不存在,就转给 /index.php,导致错误页被框架处理而非直接返回。
- 在
server块中,单独声明一个 location 匹配错误页路径:location = /404.html { internal; }
其中internal表示仅限内部跳转(如 error_page 触发),禁止用户直接访问 - 或者更稳妥:把错误页放在独立子目录(如
/error/404.html),并在error_page中写完整路径:error_page 404 = /error/404.html;,再加location ^~ /error/ { internal; } - 检查宝塔等面板是否启用了「防跨站攻击(open_basedir)」——若开启,需将错误页路径加入白名单,否则 Nginx 静默失败
验证 PHP 确实返回了 404 状态码
fastcgi_intercept_errors 只对 FastCGI 后端(即 PHP)返回的状态码起作用。如果框架没正确设置 HTTP 状态,Nginx 就无从拦截。
- 在 ThinkPHP 中,确保控制器里调用了
abort(404)或response()->code(404),而非仅输出文字 - 用 curl 测试:
curl -I https://yoursite.com/nonexistent-route,观察响应头是否有HTTP/1.1 404 Not Found - 若返回的是 200,则问题在 PHP 层,需先修复框架逻辑,
fastcgi_intercept_errors再有效

















