遇到致命异常时如何让 php 返回 500?
Posted
技术标签:
【中文标题】遇到致命异常时如何让 php 返回 500?【英文标题】:How can I get php to return 500 upon encountering a fatal exception? 【发布时间】:2010-12-06 01:35:04 【问题描述】:php 致命错误以状态码 200 的形式返回给 HTTP 客户端。如何让它返回状态码 500(内部服务器错误)?
【问题讨论】:
php 返回的错误与您在浏览器中获得的 html 标头无关。如果您从命令行运行该脚本,您将不会收到任何 200 错误代码 请参阅***.com/questions/2331582/catch-php-fatal-error 以获得解决方案。 我需要完全相反的。我设置了一个关闭函数,使用auto_prepend_file
捕获所有致命错误。但是,我还希望在调用该函数时发送status code 200
。但我不断收到status code 500
。
【参考方案1】:
header("HTTP/1.1 500 Internal Server Error");
【讨论】:
您必须手动指定 HTTP 版本才能发出状态码,这很愚蠢。 @DrewSears 我不认为你“必须”这样做;您可以像在 CGI 中一样使用Status
标头字段。但必须说,对于不熟悉 CGI 的 PHP 程序员,“HTTP/1.1”语法更容易阅读,因为它模仿了 HTTP 响应。
由于 PHP >= 5.4 有 http_response_code([int $responseCode])
函数。【参考方案2】:
这正是我昨天遇到的问题,我找到了解决方案如下:
1) 首先,您需要捕获PHP 致命错误,即错误类型E_ERROR。发生此错误时,脚本将存储错误并终止执行。您可以通过调用函数 error_get_last() 来获取存储的错误。
2) 在脚本终止之前,回调函数 register_shutdown_function() 将始终被调用。所以你需要通过这个函数注册一个错误处理程序来做你想做的事情,在这种情况下,返回标题 500 和自定义的内部错误页面(可选)。
function my_error_handler()
$last_error = error_get_last();
if ($last_error && $last_error['type']==E_ERROR)
header("HTTP/1.1 500 Internal Server Error");
echo '...';//html for 500 page
register_shutdown_function('my_error_handler');
注意:如果你想捕获以 E_USER* 开头的自定义错误类型,你可以使用函数 set_error_handler() 注册错误处理程序,并通过函数 trigger_error 触发错误,但是这个错误处理程序不能处理 E_ERROR 错误类型。请参阅 php.net 上关于 error handler 的说明
【讨论】:
一定要在生产环境中也使用ini_set("display_errors", "off");
,否则致命错误信息会被发回客户端。
我建议也检查 E_PARSE - 这也可以通过这种方式捕获,前提是在包含解析错误的文件之前设置了关闭功能。【参考方案3】:
标准 PHP 配置会在发生错误时返回 500!只需确保您的 display_errors = off。你可以模拟它:
ini_set('display_errors', 0);
noFunction();
生产时 display_errors 指令默认关闭。
【讨论】:
这应该更高。这实际上是设置服务器以在致命错误时返回 500 的正确方法。如果您需要查看错误消息,您应该使用错误日志。【参考方案4】:我使用“set_exception_handler”来处理未捕获的异常。
function handleException($ex)
error_log("Uncaught exception class=" . get_class($ex) . " message=" . $ex->getMessage() . " line=" . $ex->getLine());
ob_end_clean(); # try to purge content sent so far
header('HTTP/1.1 500 Internal Server Error');
echo 'Internal error';
set_exception_handler('handleException');
【讨论】:
如果你想处理致命错误可以这样做:***.com/questions/277224/… 同时使用 set_error_handler 和 set_exception_handler。第一个用于旧式致命错误,第二个用于面向对象的异常。【参考方案5】:自 PHP >= 5.4
http_response_code(500);
echo json_encode( [ 'success' => false , 'message' => 'Crazy thing just happened!' ]);
exit();
请在echo
之前设置httpCode。
【讨论】:
【参考方案6】:根据 PHP 文档,无法以任何方式处理 PHP E_ERROR: http://www.php.net/manual/en/function.set-error-handler.php
根据该链接,也无法处理“E_PARSE、E_CORE_ERROR、E_CORE_WARNING、E_COMPILE_ERROR、E_COMPILE_WARNING 和大部分 E_STRICT”。
您可以为包括 E_USER_ERROR 在内的其他错误、警告和通知提供处理程序,但这实际上并没有听起来那么有用,因为此错误只是由程序员使用 trigger_error() 故意抛出的。
当然,您可以捕获任何异常(甚至是原生 PHP 函数抛出的异常)。
我同意这是一个问题。当应用程序代码崩溃和烧毁时,服务器不应返回 200 OK。
【讨论】:
在这里回复超级旧的答案...但是从 php 5.2 开始...您可以在关闭函数中使用error_get_last()
.. 如果最后一个错误是致命的.. tada【参考方案7】:
可以使用php错误处理
http://www.w3schools.com/php/php_error.asp
【讨论】:
好的答案不仅仅是链接到其他页面。例如,您可以很快参考该页面。当目标站点关闭或他们移动该内容时会发生什么?此外,w3schools 也不是很好的来源。【参考方案8】:您必须使用 try/catch 捕获抛出的错误,然后使用该 catch 块发送带有 500 错误的 header()。
try
...badcode...
throw new Exception('error');
catch (Exception $e)
header("Status: 500 Server Error");
var_dump($e->getMessage());
如果致命异常没有被 try catch 块包围,那么您必须注册一个全局处理程序并使用register_shutdown_function()
在脚本结束时检查错误。
【讨论】:
这将捕获异常,但不会捕获 PHP 致命错误,这些错误是在异常范围之外处理的。 据我所知,无法通过错误处理或异常处理来捕获致命/语法错误 @ChrisRamakers:我读过一些关于使用输出处理程序捕获 PHP 致命错误的内容。 取决于,语法错误是在编译时触发的,因此处理输出或异常处理简单的逻辑永远不会发生,因为页面根本没有执行,因为我无法编译。但同样,我不是绝对的专家,所以我可能不知道你在谈论的输出处理程序 其实你是用register_shutdown_function()
来捕捉E_FATAL错误的。【参考方案9】:
永远不要忘记将header("HTTP/1.1 200 OK", true, 200);
设置为任何执行路径的最后一行:
//first things first:
header("HTTP/1.1 500 Internal Server Error", true, 500);
//Application code, includes, requires, etc. [...]
//somewhere something happens
//die();
throw new Exception("Uncaught exception!");
//last things last, only reached if code execution was not stopped by uncaught exception or some fatal error
header("HTTP/1.1 200 OK", true, 200);
在PHP 5.4
中,您可以将上面的header
函数替换为更好的http_response_code(200)
或http_response_code(500)
。
【讨论】:
如果在第一次和最后一次header()
调用之间生成任何输出,那将不起作用,因为那时标头已经发送。工作页面可能会以状态 500 交付。这种方法风险太大。
使用输出缓冲并在头部之后输出。这是显而易见的。如果输出缓冲以任何方式失败,那不是一个工作页面,它是一个有问题的页面。【参考方案10】:
处理致命错误(编译错误,例如缺少分号)时的困难在于脚本不会被执行,因此在该脚本中设置状态码无济于事。但是,当您包含或需要脚本时,将执行调用脚本,而不管包含的脚本中是否有错误。有了这个,我得出了这个解决方案:
rock-solid-script.php:
// minimize changes to this script to keep it rock-solid
http_response_code(500); // PHP >= 5.4
require_once("script-i-want-to-guard-for-errors.php");
script-i-want-to-guard-for-errors.php:
// do all the processsing
// don't produce any output
// you might want to use output buffering
http_response_code(200); // PHP >= 5.4
// here you can produce the output
将您的调用指向 rock-solid-script.php,然后您就可以开始了。
我希望在 .htaccess 中将默认状态代码设置为 500 会更好。这对我来说似乎更优雅,但我找不到办法把它拉下来。我尝试了 RewriteRule R-flag,但这完全阻止了 php 的执行,所以没有用。
【讨论】:
以上是关于遇到致命异常时如何让 php 返回 500?的主要内容,如果未能解决你的问题,请参考以下文章