问题
In REST API a 200 response show a successful operation. PHP by default output the error message directly in the response body without changing response code. In SPAs, the response text is not directly visible to user. So when the application does not work as expected I have check response body through FireBug to check for possible PHP exceptions (which cause invalid json response). Is there any way to send a specific HTTP code on all PHP errors?
Is there any way to change the HTTP response code according to existence of any PHP errors? Or, is it possible to grab the error text and send it in json format in a hassle-free way. (in development phase)
Update: Exception Catching (try/catch/final) is not what I am looking for.
回答1:
Let say, for example, that you are only concerned about fatal run-time errors, fatal compile-time errors and run-time warnings. Set the error reporting to desired level with error_reporting() function.
error_reporting( E_ERROR | E_COMPILE_ERROR | E_WARNING );
Since user-defined error handler ( later below ) can't handle fatal errors, fatal error messages will still be displayed. To avoid that use ini_set() function and set the display_errors
to zero.
ini_set( 'display_errors', 0 );
Now create a custom error handler with set_error_handler() to completely bypass PHP error handler for the error types specified ( does not apply to fatal errors ).
/* The following error types cannot be handled with a user defined function:
* E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING
* The standard PHP error handler is completely bypassed for the error types specified
* unless the callback function returns FALSE.
*/
function exception_error_handler( $severity, $message, $file, $line )
{
if ( !( error_reporting() & $severity ) ) {
// This error code is not included in error_reporting
return;
}
// code for handling errors
}
set_error_handler( "exception_error_handler" );
Fatal errors can be handled on shutdown with register_shutdown_function(). Shutdown handler is executed after the script is done, or is terminated ( this also applies for errors ). We need to get the information about the last error that occurred ( error_get_last() ), next is to check if this is the type of error that we track ( that it is not really needed here since errors that are not specified in error_reporting
won't be triggered, but it can be useful to filter errors ), and lastly, call to exception handler.
function fatal_error_shutdown()
{
$last_error = error_get_last();
if ( error_reporting() & $last_error['type'] )
call_user_func_array( 'exception_error_handler', $last_error );
}
register_shutdown_function( 'fatal_error_shutdown' );
Now you can use custom exception handler to catch unhandled exceptions ( including fatal ones ) and to force the response code ( with header() function ).
回答2:
Of course you can change HTTP status in PHP:
<?php
header("HTTP/1.1 502 Bad Gateway");
?>
You could change the message and the code, but you must to be careful with standard codes
回答3:
set_error_handler
function is what I missed. I came up with the following code. Any better answer is welcomed.
function jsonErrorHandler()
{
if (error_reporting()) {
http_response_code(500);
header('Content-Type: application/json; charset=utf-8');
$response = array_combine(['errno', 'errstr', 'errfile', 'errline', 'errcontext'], func_get_args());
die(json_encode($response));
}
}
set_error_handler('jsonErrorHandler');
回答4:
Use a framework or an error handler library.
Depending on which framework you choose you can customize how that error handler presents the errors. The error handler I linked to apparently supports serializing errors into JSON by default, you should check out its documentation.
With a framework, here's an example for Laravel 4 :
App::error(function(Exception $exception, $code) {
Log::error($exception);
return Response::json(["code" => $code, "message" => $exception->getMessage()], $code);
});
Note that if you rely on the global error handler there's usually a problem elsewhere - you should not rely on it to handle your errors; instead use try/catch where appropriate.
回答5:
Though some part of your question is answered here Returning http status codes with a rest api
I would suggest not to send a different http code for the many warnings, errors, and notices. A 500(http code 500) internal server error should do and you do not need to expose the specifics of the error to your API consumers. Ofcourse you can log all the errors/notices/warnings for debugging and fixing your application.
Also, it depends on your application logic too as to which errors need to be reported to the users like data validation, business logic etc.
回答6:
You can use register_shutdown_function()
with error_get_last()
PHP functions for catch any errors and return valid response. There is a working example that using in RockWall REST engine
回答7:
The HTTP Status Code is sent in the headers of the HTTP response, which means you can change it whenever you want as long as PHP hasn't sent any byte to the client. If it already did, you will most likely get a Cannot modify header information - headers already sent error.
PHP have several functions to change the status code, I would recommand http_response_code(), since it's easier to use: you only need to send the HTTP Status Code and it will write the full header for you.
To catch errors, I would suggest setting an error handler.
function log_error($errno, $errstr, $errfile = '', $errline = 0, $errcontext = array())
{
// Save the error to the error log.
// You may want to add more information than $errstr in the log, so feel free to change this line.
error_log($errstr);
// If headers haven't been sent, you can set a new one.
if (!headers_sent())
{
// 500 is the most generic error when the error comes from your application.
http_response_code(500);
// Checking if you're in debug mode allows you to show you errors while developping, and hiding them for users.
// Change this line by your own checks.
if (IS_DEBUG)
{
// Send the correct Content-Type header.
header('Content-Type: application/json; charset=utf-8');
// Sending information about the error.
echo json_encode(array(
'error' => $errstr // Once again, you may want to add more information.
));
// Exiting since we do not want the script to continue.
exit;
}
else
{
// Do whatever you want here, it will be shown to your users if you're not in debug mode.
// But do not forget to exit.
exit;
}
}
}
// Setting your function as an error handler.
set_error_handler('error_handler');
Since exceptions are not handled by the error handler in PHP, I would also suggest to set an exception handler.
Every PHP error encountered by your application during runtime (this excludes parse errors for example) will now send a 500 Internal Server Error
response, with details about the error if you want to.
回答8:
In Yii Framework, Handling such issues very efficiently.
They have used PHP's set_exception_handler('exceptionHandlerFunction') and set_error_handler('errorHandlerFunction') function to handle all types of Exceptions and Errors (Warnings, Notice) repectively.
On FATAL Error, register_shutdown_function('fatalHandlerFunction')
Now, for display purpose, Yii is doing very efficiently.
In error/exception/fatal handler function, It's upto configuration to either throw error to client side OR display well formatted error.
If want to display well formatted then, Yii is transfering route to SystemController's Error action.
You can also go through with How Yii Handling Errors.
Hope it helps !!
来源:https://stackoverflow.com/questions/29959986/how-to-handle-php-notices-warnings-and-errors-in-rest-api