错误

未匹配的标注

错误处理

介绍

当你开始一个新的 Laravel 项目时, 它已经为您配置了错误和异常处理。 App\Exceptions\Handler 类用于记录应用程序触发的所有异常,然后将其呈现回用户。我们将在本文中深入讨论这个类。

配置

你的 config/app.php 配置文件中的 debug 选项决定了对于一个错误实际上将显示多少信息给用户。默认情况下,该选项的设置将遵照存储在 .env 文件中的 APP_DEBUG 环境变量的值。

对于本地开发,你应该将 APP_DEBUG 环境变量的值设置为 true。在生产环境中,该值应始终为 false。如果在生产中将该值设置为 true,则可能会将敏感配置值暴露给应用程序的终端用户。

异常处理

Report 方法

所有异常都是由 App\Exceptions\Handler 处理。 这个类包含了两个方法:reportrender。我们将详细的剖析这些方法。report 方法用于记录异常或将它们发送给如 FlareBugsnagSentry 等外部服务。默认情况下,将根据你的 日志 配置来记录异常。不过,你可以用任何自己喜欢的方式来记录异常。

例如,如果您需要使用不同的方式来报告不同的异常,您可以使用 reportable 方法来注册一个闭包,当需要报告给定的异常的时候便会执行它。 Laravel 将通过检查闭包的类型提示来判断闭包报告的异常类型:

use App\Exceptions\CustomException;

/**
 * 在应用中在注册一个异常处理回调
 *
 * @return void
 */
public function register()
{
    $this->reportable(function (CustomException $e) {
        //
    });
}

当您使用 reportable 方法注册一个自定义异常报告回调时, Laravel 依然会使用默认的日志配置记录下应用异常。 如果您想要在默认的日志堆栈中停止这个行为,您可以在定义报告回调时使用 stop 方法:

$this->reportable(function (CustomException $e) {
    //
})->stop();

技巧:要为给定的异常自定义异常报告,您可以使用 可报告异常

全局日志上下文

在可用的情况下, Laravel 会自动将当前用户的编号作为数据添加到每一条异常日志信息中。您可以通过重写 App\Exceptions\Handler 类中的 context 方法来定义您自己的全局上下文数据(环境变量)。此后,每一条异常日志信息都将包含这个信息:

/**
 * 获取默认日志的上下文变量
 *
 * @return array
 */
protected function context()
{
    return array_merge(parent::context(), [
        'foo' => 'bar',
    ]);
}

report 辅助函数

有时,您可能需要报告异常,但不终止当前请求的处理。report 辅助函数允许您在不渲染错误页面的情况下快速报告异常:

public function isValid($value)
{
    try {
        // 校验值...
    } catch (Throwable $e) {
        report($e);

        return false;
    }
}

按类型忽略异常

异常处理器的 $dontReport 属性包含了一个不会被日志记录的异常类型的数组。例如,由 404 错误导致的其他类型的错误就不会被写到日志文件中。您可以按需添加其他异常类型到该数组中:

/**
 * 一个不会被报告的异常类型的列表
 *
 * @var array
 */
protected $dontReport = [
    \Illuminate\Auth\AuthenticationException::class,
    \Illuminate\Auth\Access\AuthorizationException::class,
    \Symfony\Component\HttpKernel\Exception\HttpException::class,
    \Illuminate\Database\Eloquent\ModelNotFoundException::class,
    \Illuminate\Validation\ValidationException::class,
];

渲染异常

默认情况下, Laravel 异常处理器会自动为您转换异常为 HTTP 响应。当然,您亦可在异常处理器的 renderable 方法中注册一个特定类型的异常的自定义渲染闭包来实现。Laravel 将会根据闭包的类型提示来确定异常的类:

use App\Exceptions\CustomException;

/**
 * 注册异常处理回调
 *
 * @return void
 */
public function register()
{
    $this->renderable(function (CustomException $e, $request) {
        return response()->view('errors.custom', [], 500);
    });
}

Reportable & Renderable 异常

除了在异常处理器的 reportrender 方法中检查异常类型外,您也可以直接在您的自定义异常中定义 reportrender 方法。当定义了这些方法时,它们将被框架自动调用:

<?php

namespace App\Exceptions;

use Exception;

class RenderException extends Exception
{
    /**
     * 报告异常
     *
     * @return void
     */
    public function report()
    {
        //
    }

    /**
     * 渲染异常为 HTTP 响应
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function render($request)
    {
        return response(...);
    }
}

如果您的异常包含了仅在满足某些条件时才报告的自定义报告逻辑,您可能需要指示 Laravel 使用默认的异常处理配置去报告它。您可以在异常的 report 方法中返回 false 以实现之:

/**
 * 报告异常
 *
 * @return bool|void
 */
public function report()
{
    // 判断异常是否需要自定义报告...

    return false;
}

技巧:您可以通过类型提示传递任意的依赖到 report 方法中,它们将被 Laravel 的 服务容器 自动注入到方法中。

HTTP 异常

某些异常描述了服务器的 HTTP 错误代码。例如,错误(404)代表「页面未找到」,错误(401)代表「未经授权的错误」甚至是开发者造成的 500 错误。要在应用的任何地方生成这样的响应,您可以使用 abort 辅助函数:

abort(404);

abort 辅助函数将会立即抛出一个由异常处理器渲染的异常。当然,您也可以为响应提供一个文本,不过,这是可选的:

abort(403, 'Unauthorized action.');

自定义 HTTP 错误页面

Laravel 创建了可以轻松显示各种 HTTP 状态码的自定义错误页面。例如,如果您想要自定义 HTTP 状态码为 404 的错误页面,您只需创建 resources/views/errors/404.blade.php 文件。该文件用于您的应用产生的所有 404 错误。该目录中的视图应与它们所对应的 HTTP 状态码。由 abort 函数引发的 HttpException 实例将作为 exception 变量传递给视图:

<h2>{{ $exception->getMessage() }}</h2>

您可以使用 vendor:publish Artisan 命令发布 Laravel 错误页面模板。一旦您发布了模板,您就可以像下面这样自定义它们:

php artisan vendor:publish --tag=laravel-errors

本文章首发在 LearnKu.com 网站上。

本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
上一篇 下一篇
Summer
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
贡献者:3
讨论数量: 0
发起讨论 只看当前版本


暂无话题~