错误处理
Introduction
当你开始一个新的 Laravel 项目时,错误和异常处理已经为你配置好了。这App\Exceptions\Handler
类是记录应用程序抛出的所有异常,然后呈现给用户的地方。我们将在本文档中更深入地研究此类。
Configuration
这debug
你的选项config/app.php
配置文件决定了有多少关于错误的信息实际显示给用户。默认情况下,此选项设置为尊重APP_DEBUG
环境变量,存储在你的.env
文件。
在本地开发期间,您应该设置APP_DEBUG
环境变量到true
.在您的生产环境中,此值应始终为false
.如果该值设置为true
在生产中,您冒着将敏感配置值暴露给应用程序最终用户的风险。
异常处理器
报告异常
所有异常都由App\Exceptions\Handler
班级。这个类包含一个register
您可以在其中注册自定义异常报告和呈现回调的方法。我们将详细研究这些概念中的每一个。异常报告用于记录异常或将它们发送到外部服务,如Flare,Bugsnag 或者Sentry.默认情况下,将根据您的记录记录异常logging 配置。但是,您可以随意记录异常。
例如,如果您需要以不同的方式报告不同类型的异常,您可以使用reportable
方法来注册一个闭包,当需要报告给定类型的异常时应该执行该闭包。 Laravel 将通过检查闭包的类型提示来推断闭包报告的异常类型:
use App\Exceptions\InvalidOrderException;
/**
* Register the exception handling callbacks for the application.
*/
public function register(): void
{
$this->reportable(function (InvalidOrderException $e) {
// ...
});
}
当您使用注册自定义异常报告回调时reportable
方法,Laravel 仍然会使用应用程序的默认日志记录配置来记录异常。如果您希望停止将异常传播到默认日志记录堆栈,您可以使用stop
定义报告回调或返回时的方法false
从回调:
$this->reportable(function (InvalidOrderException $e) {
// ...
})->stop();
$this->reportable(function (InvalidOrderException $e) {
return false;
});
Note
要自定义给定异常的异常报告,您还可以使用可报告的异常.
全局日志上下文
如果可用,Laravel 会自动将当前用户的 ID 作为上下文数据添加到每个异常的日志消息中。您可以通过覆盖context
你的应用程序的方法App\Exceptions\Handler
班级。此信息将包含在您的应用程序编写的每个异常日志消息中:
/**
* Get the default context variables for logging.
*
* @return array<string, mixed>
*/
protected function context(): array
{
return array_merge(parent::context(), [
'foo' => 'bar',
]);
}
异常日志上下文
虽然向每条日志消息添加上下文可能很有用,但有时特定异常可能具有您希望包含在日志中的独特上下文。通过定义一个context
在您的应用程序的自定义异常之一上使用方法,您可以指定与该异常相关的任何数据,这些数据应添加到异常的日志条目中:
<?php
namespace App\Exceptions;
use Exception;
class InvalidOrderException extends Exception
{
// ...
/**
* Get the exception's context information.
*
* @return array<string, mixed>
*/
public function context(): array
{
return ['order_id' => $this->orderId];
}
}
这report
帮手
有时您可能需要报告异常但继续处理当前请求。这report
辅助函数允许您通过异常处理程序快速报告异常,而无需向用户呈现错误页面:
public function isValid(string $value): bool
{
try {
// Validate the value...
} catch (Throwable $e) {
report($e);
return false;
}
}
异常日志级别
当消息写入您的应用程序时logs,消息被写在一个指定的日志级别,它表示正在记录的消息的严重性或重要性。
如上所述,即使您使用reportable
方法,Laravel 仍然会使用应用程序的默认日志记录配置来记录异常;但是,由于日志级别有时会影响记录消息的通道,因此您可能希望配置记录某些异常的日志级别。
为此,您可以在$levels
应用程序异常处理程序的属性:
use PDOException;
use Psr\Log\LogLevel;
/**
* A list of exception types with their corresponding custom log levels.
*
* @var array<class-string<\Throwable>, \Psr\Log\LogLevel::*>
*/
protected $levels = [
PDOException::class => LogLevel::CRITICAL,
];
按类型忽略异常
在构建您的应用程序时,会有一些类型的异常您只想忽略并且从不报告。您的应用程序的异常处理程序包含$dontReport
初始化为空数组的属性。您添加到此属性的任何类都不会被报告;但是,它们可能仍然具有自定义呈现逻辑:
use App\Exceptions\InvalidOrderException;
/**
* A list of the exception types that are not reported.
*
* @var array<int, class-string<\Throwable>>
*/
protected $dontReport = [
InvalidOrderException::class,
];
在内部,Laravel 已经为您忽略了某些类型的错误,例如 404 HTTP 错误或无效 CSRF 令牌生成的 419 HTTP 响应导致的异常。如果你想指示 Laravel 停止忽略给定类型的异常,你可以调用stopIgnoring
异常处理程序中的方法register
方法:
use Symfony\Component\HttpKernel\Exception\HttpException;
/**
* Register the exception handling callbacks for the application.
*/
public function register(): void
{
$this->stopIgnoring(HttpException::class);
// ...
}
渲染异常
默认情况下,Laravel 异常处理程序会为您将异常转换为 HTTP 响应。但是,您可以自由地为给定类型的异常注册自定义呈现闭包。您可以通过调用renderable
异常处理程序中的方法。
闭包传递给renderable
方法应该返回一个实例Illuminate\Http\Response
,这可以通过生成response
帮手。 Laravel 将通过检查闭包的类型提示来推断闭包呈现的异常类型:
use App\Exceptions\InvalidOrderException;
use Illuminate\Http\Request;
/**
* Register the exception handling callbacks for the application.
*/
public function register(): void
{
$this->renderable(function (InvalidOrderException $e, Request $request) {
return response()->view('errors.invalid-order', [], 500);
});
}
您也可以使用renderable
方法来覆盖内置 Laravel 或 Symfony 异常的渲染行为,例如NotFoundHttpException
.如果关闭给renderable
方法没有返回值,将使用 Laravel 默认的异常渲染:
use Illuminate\Http\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* Register the exception handling callbacks for the application.
*/
public function register(): void
{
$this->renderable(function (NotFoundHttpException $e, Request $request) {
if ($request->is('api/*')) {
return response()->json([
'message' => 'Record not found.'
], 404);
}
});
}
可报告和可渲染的异常
而不是在异常处理程序中定义自定义报告和呈现行为register
方法,你可以定义report
和render
直接在您的自定义异常上的方法。当这些方法存在时,它们将被框架自动调用:
<?php
namespace App\Exceptions;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class InvalidOrderException extends Exception
{
/**
* Report the exception.
*/
public function report(): void
{
// ...
}
/**
* Render the exception into an HTTP response.
*/
public function render(Request $request): Response
{
return response(/* ... */);
}
}
如果你的异常扩展了一个已经可以渲染的异常,例如内置的 Laravel 或 Symfony 异常,你可以返回false
来自异常的render
呈现异常的默认 HTTP 响应的方法:
/**
* Render the exception into an HTTP response.
*/
public function render(Request $request): Response|bool
{
if (/** Determine if the exception needs custom rendering */) {
return response(/* ... */);
}
return false;
}
如果您的异常包含仅在满足特定条件时才需要的自定义报告逻辑,您可能需要指示 Laravel 有时使用默认异常处理配置报告异常。为此,您可以返回false
来自异常的report
方法:
/**
* Report the exception.
*/
public function report(): bool
{
if (/** Determine if the exception needs custom reporting */) {
// ...
return true;
}
return false;
}
Note
您可以键入提示任何所需的依赖项report
方法,它们将被 Laravel 自动注入到方法中服务容器.
HTTP 异常
一些异常描述来自服务器的 HTTP 错误代码。例如,这可能是“找不到页面”错误 (404)、“未经授权的错误”(401) 甚至是开发人员生成的 500 错误。为了从应用程序的任何地方生成这样的响应,您可以使用abort
帮手:
abort(404);
自定义 HTTP 错误页面
Laravel 可以轻松显示各种 HTTP 状态代码的自定义错误页面。例如,如果您希望自定义 404 HTTP 状态代码的错误页面,请创建一个resources/views/errors/404.blade.php
查看模板。该视图将在您的应用程序生成的所有 404 错误上呈现。此目录中的视图应命名为与它们对应的 HTTP 状态代码相匹配。这Symfony\Component\HttpKernel\Exception\HttpException
由提出的实例abort
函数将作为一个传递给视图$exception
多变的:
<h2>{{ $exception->getMessage() }}</h2>
你可以使用发布 Laravel 的默认错误页面模板vendor:publish
工匠命令。模板发布后,您可以根据自己的喜好自定义它们:
php artisan vendor:publish --tag=laravel-errors
后备 HTTP 错误页面
您还可以为给定的一系列 HTTP 状态代码定义一个“回退”错误页面。如果发生的特定 HTTP 状态代码没有相应的页面,将呈现此页面。为此,定义一个4xx.blade.php
模板和一个5xx.blade.php
应用程序中的模板resources/views/errors
目录。