错误处理
事情总会出错。你无法预测错误,但可以预期它们的出现。每个 Slim Framework 应用程序都有一个错误处理器,它接收所有未捕获的 PHP 异常。此错误处理器还会接收当前的 HTTP 请求和响应对象。错误处理器必须准备并返回适当的响应对象以返回给 HTTP 客户端。
使用方法
<?php
use Slim\Factory\AppFactory;
require __DIR__ . '/../vendor/autoload.php';
$app = AppFactory::create();
/**
* 路由中间件应该在ErrorMiddleware之前添加
* 否则从路由抛出的异常将不会被中间件处理
*/
$app->addRoutingMiddleware();
/**
* 添加 Error Middleware
*
* @param bool $displayErrorDetails -> 在生产环境中应该设置为 false
* @param bool $logErrors -> 传递给默认的 ErrorHandler 的参数
* @param bool $logErrorDetails -> 在错误日志中显示错误详细信息
* @param LoggerInterface|null $logger -> 可选的 PSR-3 日志记录器
*
* 注意:这个中间件应该最后添加。它将不会处理添加在它之后的任何中间件引发的异常/错误。
*/
$errorMiddleware = $app->addErrorMiddleware(true, true, true);
// ...
$app->run();
添加自定义错误处理器
你现在可以为任何类型的异常或 Throwable 映射自定义处理器。
<?php
use Psr\Http\Message\ServerRequestInterface;
use Psr\Log\LoggerInterface;
use Slim\Factory\AppFactory;
use Slim\Psr7\Response;
require __DIR__ . '/../vendor/autoload.php';
$app = AppFactory::create();
// 添加路由中间件
$app->addRoutingMiddleware();
// 定义自定义错误处理器
$customErrorHandler = function (
ServerRequestInterface $request,
Throwable $exception,
bool $displayErrorDetails,
bool $logErrors,
bool $logErrorDetails,
?LoggerInterface $logger = null
) use ($app) {
$logger->error($exception->getMessage());
$payload = ['error' => $exception->getMessage()];
$response = $app->getResponseFactory()->createResponse();
$response->getBody()->write(
json_encode($payload, JSON_UNESCAPED_UNICODE)
);
return $response;
};
// 添加 Error Middleware
$errorMiddleware = $app->addErrorMiddleware(true, true, true);
$errorMiddleware->setDefaultErrorHandler($customErrorHandler);
// ...
$app->run();
错误日志记录
如果你想将自定义错误日志记录到 Slim 默认的 ErrorHandler 中,有两种方法可以实现。
使用第一种方法,你可以简单地继承 ErrorHandler 并存根化 logError() 方法。
<?php
namespace MyApp\Handlers;
use Slim\Handlers\ErrorHandler;
class MyErrorHandler extends ErrorHandler
{
protected function logError(string $error): void
{
// 插入自定义的错误日志记录函数
}
}
<?php
use MyApp\Handlers\MyErrorHandler;
use Slim\Factory\AppFactory;
require __DIR__ . '/../vendor/autoload.php';
$app = AppFactory::create();
// 添加路由中间件
$app->addRoutingMiddleware();
// 实例化你的自定义错误处理器
$myErrorHandler = new MyErrorHandler($app->getCallableResolver(), $app->getResponseFactory());
// 添加 Error Middleware
$errorMiddleware = $app->addErrorMiddleware(true, true, true);
$errorMiddleware->setDefaultErrorHandler($myErrorHandler);
// ...
$app->run();
使用第二种方法,你可以提供一个符合 PSR-3标准 的日志记录器,比如流行的 Monolog 库中的日志记录器。
<?php
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use MyApp\Handlers\MyErrorHandler;
use Slim\Factory\AppFactory;
require __DIR__ . '/../vendor/autoload.php';
$app = AppFactory::create();
// 添加路由中间件
$app->addRoutingMiddleware();
// Monolog 示例
$logger = new Logger('app');
$streamHandler = new StreamHandler(__DIR__ . '/var/log', 100);
$logger->pushHandler($streamHandler);
// 添加含有日志记录器的 Error Middleware
$errorMiddleware = $app->addErrorMiddleware(true, true, true, $logger);
// ...
$app->run();
错误处理/渲染
渲染最终与处理解耦。它仍然会根据 ErrorRenderers 的帮助检测内容类型,并适当地进行渲染。
核心 ErrorHandler 扩展了完全重构的 AbstractErrorHandler 类。
默认情况下,它将调用适用于支持的内容类型的适当 ErrorRenderer 。核心 ErrorHandler 为以下内容类型定义了渲染器:
application/jsonapplication/xml和text/xmltext/htmltext/plain
对于任何内容类型,您可以注册自己的错误渲染器。首先定义一个实现 \Slim\Interfaces\ErrorRendererInterface 的新错误渲染器。
<?php
use Slim\Interfaces\ErrorRendererInterface;
use Throwable;
class MyCustomErrorRenderer implements ErrorRendererInterface
{
public function __invoke(Throwable $exception, bool $displayErrorDetails): string
{
return 'My awesome format';
}
}
text/html 内容类型的渲染器。
<?php
use MyApp\Handlers\MyErrorHandler;
use Slim\Factory\AppFactory;
require __DIR__ . '/../vendor/autoload.php';
$app = AppFactory::create();
// 添加路由中间件
$app->addRoutingMiddleware();
// 添加 Error Middleware
$errorMiddleware = $app->addErrorMiddleware(true, true, true);
// 获取默认的错误处理器并注册我自定义的错误渲染器。
$errorHandler = $errorMiddleware->getDefaultErrorHandler();
$errorHandler->registerErrorRenderer('text/html', MyCustomErrorRenderer::class);
// ...
$app->run();
强制指定错误渲染的特定内容类型
默认情况下,错误处理器尝试使用请求的 Accept 头来检测错误渲染器。如果你需要强制错误处理器使用特定的错误渲染器,可以使用以下代码:
$errorHandler->forceContentType('application/json');
新的 HTTP 异常
我们在应用程序中添加了命名的 HTTP 异常。这些异常与原生渲染器完美配合使用。它们都可以具有 description 和 title 属性,以在调用原生 HTML 渲染器时提供更多的信息。
基类 HttpSpecializedException 继承自 Exception ,并带有以下子类:
- HttpBadRequestException
- HttpForbiddenException
- HttpInternalServerErrorException
- HttpMethodNotAllowedException
- HttpNotFoundException
- HttpNotImplementedException
- HttpUnauthorizedException
如果需要任何基础存储库未提供的响应代码,可以扩展 HttpSpecializedException 类。例如,如果您希望创建一个行为与原生异常相同的504网关超时异常,可以执行以下操作:
class HttpGatewayTimeoutException extends HttpSpecializedException
{
protected $code = 504;
protected $message = 'Gateway Timeout.';
protected $title = '504 Gateway Timeout';
protected $description = 'Timed out before receiving response from the upstream server.';
}