
PHP 里 http_response_code() 和 header() 哪个该先调用
必须先调用 http_response_code()(或 header('HTTP/1.1 404 Not Found')),再调用 header('Location: /404.php')。否则重定向后状态码会变成 302,搜索引擎和 API 客户端收不到你想要的 404、500 等语义。
常见错误现象:页面跳转了,但浏览器开发者工具 Network 面板里响应状态码是 302,不是 404;curl -I 看到的是 HTTP/1.1 302 Found。
- 如果只是想显示错误页而不跳转,直接
http_response_code(404)+include '404.php'就够了 - 如果用了
header('Location: ...'),记得它默认发 302,要显式覆盖:http_response_code(404); header('Location: /404.php');—— 但注意:这其实不标准,客户端收到 404 状态却跳转,语义矛盾 - 更合理的方式是:用 302 跳转时,保持状态码为 302;真要返回 404,就别跳转,直接输出内容
Apache 下用 .htaccess 设置 ErrorDocument 的坑
PHP 层面的错误处理控制不了服务器级错误(比如 404 文件不存在、500 PHP 解析失败),这类必须靠 Web 服务器配置。Apache 的 ErrorDocument 是最常用方式,但路径容易写错。
使用场景:用户访问 /nonexistent.php,Apache 直接 404,根本没进 PHP;或者 PHP 崩溃导致 500,set_error_handler 也捕获不到。
立即学习“PHP免费学习笔记(深入)”;
功能列表:底层程序与前台页面分离的效果,对页面的修改无需改动任何程序代码。完善的标签系统,支持自定义标签,公用标签,快捷标签,动态标签,静态标签等等,支持标签内的vbs语法,原则上运用这些标签可以制作出任何想要的页面效果。兼容原来的栏目系统,可以很方便的插入一个栏目或者一个栏目组到页面的任何位置。底层模版解析程序具有非常高的效率,稳定性和容错性,即使模版中有错误的标签也不会影响页面的显示。所有的标
-
ErrorDocument 404 /errors/404.php:路径是相对于网站根目录(DocumentRoot),不是当前脚本位置 - 如果站点跑在子目录(如
http://site.com/app/),/errors/404.php仍要从根开始写,不能写成/app/errors/404.php - 确保
404.php本身能被公开访问(没被Deny from all挡住),且里面手动调用http_response_code(404),否则默认返回 200 - Nginx 没有
ErrorDocument,对应的是error_page 404 /404.html;,语法和路径逻辑不同,别套用
PHP 内部错误(Parse Error、Fatal Error)为什么 set_error_handler 捕获不到
set_error_handler 只捕获 E_WARNING、E_NOTICE 这类“可恢复”错误,对解析失败、致命错误、未捕获异常完全无效。它们发生得太早,PHP 连运行时环境都没完全起来。
真正能兜底的只有两个机制:register_shutdown_function 和 set_exception_handler,但各自有局限。
-
set_exception_handler只管未被捕获的Exception和Error(PHP 7+),不管ParseError(文件语法错) -
register_shutdown_function总会执行,可用error_get_last()判断是否发生了致命错误,但无法阻止白屏或默认错误信息输出 - 关键操作:在 shutdown 函数里检查
error_get_last()类型是否为E_PARSE或E_ERROR,然后http_response_code(500)+readfile('500.php')输出自定义页 - 注意:此时 PHP 输出缓冲可能已关闭,
echo失效,必须用readfile或打开缓冲(ob_start()得在出错前就开好)
为什么本地开发能显示自定义页,上线后又变默认 Apache 错误页
大概率是生产环境开了 display_errors = On 或 log_errors = Off,同时没关掉 Apache 的 AllowOverride None,导致 .htaccess 里的 ErrorDocument 不生效。
性能与兼容性影响:Apache 每次请求都要检查目录下有没有 .htaccess,线上关掉它能提速;但关掉后你就只能去主配置改 ErrorDocument,没法按虚拟主机或目录单独设。
- 先确认
phpinfo()里display_errors是Off,log_errors是On—— 否则错误会直接打到页面上,盖掉你的自定义页 - 检查 Apache 配置中对应目录的
AllowOverride是否包含FileInfo(ErrorDocument所需) - 用
curl -I https://yoursite.com/nonexistent看响应头,确认是否返回了你设的Location或状态码,而不是 Apache 默认文本 - CDN 或反向代理(如 Nginx 做前端)可能吞掉原始状态码,把 404 转成 200 返回给用户,这时得查中间层配置
最常被忽略的一点:自定义错误页本身出错(比如 404.php 里写了 $undefined_var->method()),会导致二次 500,最终 fallback 到服务器默认页 —— 所以错误页代码越简单越好,别引入复杂逻辑或外部依赖。










