错误处理

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 方法,你可以定义reportrender 直接在您的自定义异常上的方法。当这些方法存在时,它们将被框架自动调用:

<?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 目录。

豫ICP备18041297号-2