我有一个启用了 RESTful 的 Web 服务站点,因此其他网站/ajax 脚本可以调用该站点以获取/设置数据。但是,每当 Web 服务站点以某种方式返回 PHP 致命错误时,返回的 HTTP 状态是 200 而不是 500。有没有办法修复它,以便在发生致命错误时返回 500 而不是 200?或者,如果不可能,我如何更改我的客户端以识别 Web 服务返回的致命错误?
6 回答
PHP确实会在发生致命错误时发送 HTTP 500。让我在这个 PHP 错误报告
中引用一个评论(一个 xdebug 错误阻止了这种行为):
它确实发生了。它要求:
1) display_errors = off
2) 错误发生时尚未发送任何标头
3) 那时状态为 200。
<?
ini_set('display_errors', 0);
foobar();
// This will return a http 500
?>
您可以使用关闭函数和error_get_last捕获致命错误:
register_shutdown_function(function() {
$lastError = error_get_last();
if (!empty($lastError) && $lastError['type'] == E_ERROR) {
header('Status: 500 Internal Server Error');
header('HTTP/1.0 500 Internal Server Error');
}
});
一种可能的方法是将默认响应设置为 500,如果一切执行成功,则将响应设置为 200:
http_response_code(500);
render_my_page();
http_response_code(200);
创建自定义错误处理程序 ( set_error_handler
) 并调用header("HTTP/1.0 500 Service not available");
.
编辑:
根据我回答的第一条评论,您无法捕获真正的致命错误。但是,如果禁用了输出缓冲并且错误不显示在屏幕上,PHP 将默认为致命错误设置 500 错误代码。
<?php
$x = y();
?>
如果没有任何内容发送到屏幕,上述代码将返回 500 错误代码。
因此,如果您希望这种错误设置正确的代码,请进行自己的缓冲:
<?php
$buffer = 'blah';
$x = y(); // will trigger 500 error
echo $buffer;
?>
function fatal_error_handler() {
if (@is_array($e = @error_get_last())) {
if (isset($e['type']) && $e['type']==1) {
header("Status: 500 Internal Server Error");
header("HTTP/1.0 500 Internal Server Error");
}
}
}
register_shutdown_function('fatal_error_handler');
我开发了一种方法来捕获 PHP 中的所有错误类型(几乎所有)!我不确定 E_CORE_ERROR (我认为它不适用于该错误)!但是,对于其他致命错误(E_ERROR、E_PARSE、E_COMPILE...),仅使用一个错误处理函数就可以正常工作!这是我的解决方案:
将以下代码放在您的主文件 (index.php) 中:
<?php
define('E_FATAL', E_ERROR | E_USER_ERROR | E_PARSE | E_CORE_ERROR |
E_COMPILE_ERROR | E_RECOVERABLE_ERROR);
define('ENV', 'dev');
//Custom error handling vars
define('DISPLAY_ERRORS', TRUE);
define('ERROR_REPORTING', E_ALL | E_STRICT);
define('LOG_ERRORS', TRUE);
register_shutdown_function('shut');
set_error_handler('handler');
//Function to catch no user error handler function errors...
function shut(){
$error = error_get_last();
if($error && ($error['type'] & E_FATAL)){
handler($error['type'], $error['message'], $error['file'], $error['line']);
}
}
function handler( $errno, $errstr, $errfile, $errline ) {
switch ($errno){
case E_ERROR: // 1 //
$typestr = 'E_ERROR'; break;
case E_WARNING: // 2 //
$typestr = 'E_WARNING'; break;
case E_PARSE: // 4 //
$typestr = 'E_PARSE'; break;
case E_NOTICE: // 8 //
$typestr = 'E_NOTICE'; break;
case E_CORE_ERROR: // 16 //
$typestr = 'E_CORE_ERROR'; break;
case E_CORE_WARNING: // 32 //
$typestr = 'E_CORE_WARNING'; break;
case E_COMPILE_ERROR: // 64 //
$typestr = 'E_COMPILE_ERROR'; break;
case E_CORE_WARNING: // 128 //
$typestr = 'E_COMPILE_WARNING'; break;
case E_USER_ERROR: // 256 //
$typestr = 'E_USER_ERROR'; break;
case E_USER_WARNING: // 512 //
$typestr = 'E_USER_WARNING'; break;
case E_USER_NOTICE: // 1024 //
$typestr = 'E_USER_NOTICE'; break;
case E_STRICT: // 2048 //
$typestr = 'E_STRICT'; break;
case E_RECOVERABLE_ERROR: // 4096 //
$typestr = 'E_RECOVERABLE_ERROR'; break;
case E_DEPRECATED: // 8192 //
$typestr = 'E_DEPRECATED'; break;
case E_USER_DEPRECATED: // 16384 //
$typestr = 'E_USER_DEPRECATED'; break;
}
$message = '<b>'.$typestr.': </b>'.$errstr.' in <b>'.$errfile.'</b> on line <b>'.$errline.'</b><br/>';
if(($errno & E_FATAL) && ENV === 'production'){
header('Location: 500.html');
header('Status: 500 Internal Server Error');
}
if(!($errno & ERROR_REPORTING))
return;
if(DISPLAY_ERRORS)
printf('%s', $message);
//Logging error on php file error log...
if(LOG_ERRORS)
error_log(strip_tags($message), 0);
}
ob_start();
@include 'content.php';
ob_end_flush();
?>
我希望这可以帮助很多人!
我认为您希望在部署应用程序之前捕获并修复所有致命错误,因为其中许多是代码错误、缺少包含、不存在的对象,这些都是开发错误。即使是内存不足的错误也可以通过节省内存的编码技术来最小化(最大的胜利之一是使用无缓冲的查询并处理数据并在返回结果集时发出输出,而不是抛出巨大的数组)。