错误处理

简介

当启动新的 Laravel 项目时,已经为您配置了错误和异常处理。App\Exceptions\Handler 类会记录应用触发的所有异常,然后渲染给用户。在该文档中,我们会深入讨论此类。

配置

config/app.php 配置文件中的 debug 选项决定了实际上会显示错误的多少内容给用户。默认情况下,该选项设置为跟随环境变量 APP_DEBUG 的值,它存储在 .env 文件中。

对于本地开发,应该将环境变量 APP_DEBUG 设置为 true。在生产环境中,该值应始终设置为 false。如果在生产中将该值设置为 true,会有将敏感配置信息暴露给应用终端用户的风险。

异常处理器

report 方法

所有异常都由 App\Exceptions\Handler 类处理。该类包含两个方法:reportrender。我们会详细研究每个方法。report 方法用于记录异常或者将其发送给外部服务,如 BugsnagSentry。默认情况下,report 方法会将异常传递给记录异常的基类。不过,您可以根据需要自由记录异常。

例如,如果要用不同的方式报告不同类型的异常,可以使用 PHP 的类型运算符 instanceof

/**
 * 报告或记录异常
 *
 * 这里是一个将异常发送给 Sentry,Bugsnag 等的好地方
 *
 * @param  \Exception  $exception
 * @return void
 */
public function report(Exception $exception)
{
    if ($exception instanceof CustomException) {
        //
    }

    return parent::report($exception);
}

不要在 report 方法中进行大量的 instanceof 检查,而应考虑使用 reportable 异常

report 辅助函数

有时可能需要报告异常但仍希望继续处理当前请求。report 辅助函数使用异常处理器的 report 方法来快速报告异常,而不渲染错误页面:

public function isValid($value)
{
    try {
        // 验证该规则
    } catch (Exception $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,
];

render 方法

render 方法负责将给定的异常转换为要发送给浏览器的 HTTP 响应。默认情况下,异常会传递给生成响应的基类。不过,您可以自由检查异常类型或者返回自定义响应:

/**
 * 将异常渲染为 HTTP 响应
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Exception  $exception
 * @return \Illuminate\Http\Response
 */
public function render($request, Exception $exception)
{
    if ($exception instanceof CustomException) {
        return response()->view('errors.custom', [], 500);
    }

    return parent::render($request, $exception);
}

Reportable & Renderable 异常

不要在异常处理器的 reportrender 方法中对异常使用类型检查,而应直接在自定义异常中定义 reportrender 方法。当这些方法存在时,框架会自动调用它们:

namespace App\Exceptions;

use Exception;

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

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

HTTP 异常

一些异常描述了服务器的 HTTP 错误码。例如,可能是「未找到页面」(404),「未授权错误」(401)或者甚至是开发者生成的 500 错误。可以使用 abort 辅助函数在应用的任何位置生成类似响应:

abort(404);

abort 辅助函数会立即抛出异常处理器生成的异常。还可以提供可选的响应文本:

abort(403, 'Unauthorized action.');

自定义 HTTP 错误页面

Laravel 可以轻松显示各种 HTTP 状态码的自定义错误页面。例如,如果要为 404 HTTP 状态码自定义错误页面,创建一个 resources/views/errors/404.blade.php。应用生成的所有 404 错误都会显示该文件。该目录下的视图命名应该和对应的 HTTP 状态码相匹配。abort 函数抛出的 HttpException 实例会作为 $exception 变量传递到视图:

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