filp/whoops 这个错误处理类库有什么好处我这里就不赘述了,谁用谁知道。

Laravel 在 4.x 时代是有集成了 whoops 的,但是在 5.x 去掉了。不过作为一个 out-of-the-box 的错误处理类库,我们依然可以很方便地将 whoops 带回 Laravel 中。

网上有很多文章都讲述了 Laravel 使用 whoops 的方法,但总有些小问题(像是代码太丑了啊,代码太丑了啊之类的)。其中我认为最优雅的实现是这篇文章所描述的:Bringing Whoops Back to Laravel 5,我下面的也是基于他给出的代码修改的。


安装 whoops 之类的步骤我这里就不说了,这些在它的 README 上都有。安装完后打开 app/Exceptions/Handler.php 这个文件,进行如下修改:

/**
 * Render an exception into an HTTP response.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Exception  $e
 * @return \Illuminate\Http\Response
 */
public function render($request, Exception $e)
{
    if ($e instanceof \Illuminate\Foundation\Validation\ValidationException) {
        // quick fix for returning 422
        // @see https://prinzeugen.net/custom-responses-of-laravel-validations/
        return $e->getResponse()->setStatusCode(200);
    }

    foreach ($this->dontReport as $type) {
        if ($e instanceof $type) {
            return parent::render($request, $e);
        } else {
            // 当不处于 DEBUG 模式时隐藏错误的详细信息,防止敏感信息泄露
            if (config('app.debug')) {
                return $this->renderExceptionWithWhoops($e);
            } else {
                // 这里我们调用下面定义的方法,给用户显示一个「哎呀,出错啦」的友好页面
                // 如果你想继续使用 Laravel 默认的那个只有一句话的错误页
                // 就把下面这行改成 return parent::render($request, $e);
                return $this->renderExceptionInBrief($e);
            }
        }
    }
}

/**
 * Render an exception using Whoops.
 *
 * @param  \Exception $e
 * @return \Illuminate\Http\Response
 */
protected function renderExceptionWithWhoops(Exception $e)
{
    $whoops = new \Whoops\Run;

    // 只有在 GET 请求出错时渲染 PrettyPage,其余请求时直接渲染文本
    // 你也不想在 AJAX 请求的错误处理函数中看到一个 web 页面吧
    $handler = ($_SERVER['REQUEST_METHOD'] == "GET") ?
                    new \Whoops\Handler\PrettyPageHandler : new \Whoops\Handler\PlainTextHandler;
    $whoops->pushHandler($handler);

    return new \Illuminate\Http\Response(
        $whoops->handleException($e),
        $e->getStatusCode(),
        $e->getHeaders()
    );
}

/**
 * Render an exception in a short word.
 *
 * @param  \Exception $e
 * @return \Illuminate\Http\Response
 */
protected function renderExceptionInBrief(Exception $e)
{
    // 这里请自定义要返回的视图,其中不包含错误的详细信息
    return response()->view('errors.brief');
}

可以看到我们新添加了 renderExceptionWithWhoopsrenderExceptionInBrief 两个方法,分别适用于 APP_DEBUG 开和关的情况。

你问我为啥要覆盖 Laravel 在 APP_DEBUG 为关时的默认错误页?

DEFAULT

你要是觉得这个默认的页面好看那我也管不着咯~ 反正我是修改成下面这样了:

CUSTOM ERROR HANDLER

至于为什么要在当前为 POST 请求时使用 PlainTextHandler 渲染纯文本的堆栈信息:

AJAX

如果你渲染的是页面的话你就会在这个 Modal 里看到你的窗口了(笑)。当然,如果你没有做这样的 Ajax 错误处理的话也可以忽略这个。

那段修改 ValidationException 响应状态码为 200 的也是为了 Ajax,详情可以查看我之前写的博文:自定义 Laravel Validator 所返回的响应

最后效果如下:

whoops

以上。

除另有声明外,本博客文章均采用 知识共享(Creative Commons) 署名-非商业性使用-相同方式共享 3.0 中国大陆许可协议 进行许可。