PHP Fatal error HTTP return 200

背景

周末公司发生一个严重的问题,房源单页输出导航栏后,下面是空白的(这种情况一定是出现了 PHP Fatal error,查看 /var/log/user.log ,确实有 PHP Fatal error 错误),但是返回的HTTP code 确实 200,不是我们想象的 500。由于 HTTP 200 是一个正常的状态码,因此为我们排查错误埋下了一个大坑,导致我们不能马上发现问题。

如何诊断

发生 PHP Fatal error 时,却返回 HTTP 200 ,很难排查错误,所以这个问题一定要解决。 可以使用 strace 命令 查看 PHP 进程在这个会话期间发生了什么。

// 模拟当时的情况
<?php
ini_set("display_errors",0);
// $str=str_repeat("a",20000); http return 200
$str=str_repeat("a",200); // http return 500
echo $str;

// 不存在的方法
foo();

当发生 http 200 的时候 使用 strace 抓取的结果,可以看到当发生 http 返回 200 的时候,PHP 已经向 Nginx 输出了前面的内容Content-type: text/html <p>aaaaaaaaaaaaaaaaaaaaaa... ,

write(4, "16137370Content-type: text/html aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"..., 8192) = 8192 sendto(6, "Jul 20 13:14:45 ool www: PHP Fatal error: Call to undefined function foo() in /home/wbsong/projects/phptest/error.php on line 8", 132, MSG_NOSIGNAL, NULL, 0) = 132

当发生 500 的时候,使用 strace 抓取的结果,看以看出区别,PHP 向 Nginx 输出了 Status: 500 Internal Server Error 的信息。

write(4, "161162Status: 500 Internal Server Error Content-type: text/html aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa13110aaa", 288) = 288 shutdown(4, SHUT_WR)

所以总结起来,返回200 & 500 的区别就是在发生错误前,PHP 是否已经输出了 Header信息,是否输出 Header 取决于 output_buffering 这个参数的大小,一般默认是 4096。

总结

  • Nginx 返回的 Http 状态是PHP 决定的(200 的时候,PHP 不用明确指出)
  • 当PHP 发现缓冲区满了以后,就要向 Nginx 输出,第一次会输出 使用 header 函数设置的内容。
    • 之后如果设置 Header 是没有用的 (HTTP 协议里面规定,Header 只能出现在最前面)
    • 发生严重错误时,PHP 只能打印错误,并且向Nginx 发生终止请求(页面就会出现不全的情况)
  • 之前很少看到这种情况的原因是,错误绝大部分是发生在 Controller 层面,这个时候PHP 还没有向 Nginx 发出任何数据,所以 PHP 是可以通知 Nginx 发生了什么事情,而这次事故是 Compontent 渲染的时候发生的错误,已经有很多的输出。
  • 解决的办法最简单的方式就是调整 output_buffering ,调整成一个比较大的值,或者改代码使用 ob_start() + ob_get_clean() + error_get_last() 来解决

output_buffering 这个参数一定要在 php.ini 里面设置,通过 ini_set 是没有效果的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值