Laravel 5.2 使用自定义异常处理程序创建Laravel 404页面

当PHP发生意想不到的状况或者错误的时候就会抛出异常。经验告诉我们,异常不应该用于控制应用程序逻辑,例如 if-statements,应该是异常类的子类。

我们知道,异常可以在我们的应用程序的任何时间点被抛出。Laravel 提供了一个方便的异常处理程序类,它将检查在 laravel 应用程序中抛出的所有异常并给出相关的响应。Laravel 中使用的所有异常都扩展了异常类,使所有异常由单个类捕获的一个主要优点,我们能够创建自定义异常处理程序,根据异常返回不同的响应消息。在本教程中,我们将介绍如何在 Laravel 5.2 中创建自定义异常处理程序,以及如何根据异常返回404页面。


如何工作

在Laravel 5.2中,所有的异常和错误不管是自定义的还是默认的都是由 app/Exceptions/Handler.php 中的 handle 类处理的,它有两个方法:

report()

这个方法可以记录引发的异常或者将它们解析到错误日志引擎(如 bugsnag 或者 sentry),这里不再讨论,感兴趣的自行研究。

render()

这个方法将异常引发的错误消息生成 HTTP 响应,并将其发送给浏览器。

/**
     * 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)
    {
        return parent::render($request, $e);
    }

我们可以用自己自定义的异常处理程序覆盖默认的错误处理。

/**
 * @param  \Illuminate\Http\Request  $request
 * @param  \Exception  $e
 * @return \Illuminate\Http\Response
 */
public function render($request, Exception $e)
{
    if ($e instanceof CustomException) {
        return response()->view('errors.custom', [], 500);
    }

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

Laravel 自己会处理处理检查以确定异常的最佳响应。看看父类 Illuminate\Foundation\Exceptions\Handler, render()根据抛出的异常生成不同的响应。

   /**
     * Render an exception into a response.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Exception  $e
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function render($request, Exception $e)
    {
        if ($e instanceof HttpResponseException) {
            return $e->getResponse();
        } elseif ($e instanceof ModelNotFoundException) {
            $e = new NotFoundHttpException($e->getMessage(), $e);
        } elseif ($e instanceof AuthenticationException) {
            return $this->unauthenticated($request, $e);
        } elseif ($e instanceof AuthorizationException) {
            $e = new HttpException(403, $e->getMessage());
        } elseif ($e instanceof ValidationException && $e->getResponse()) {
            return $e->getResponse();
        }

        if ($this->isHttpException($e)) {
            return $this->toIlluminateResponse($this->renderHttpException($e), $e);
        } else {
            return $this->toIlluminateResponse($this->convertExceptionToResponse($e), $e);
        }
    }
    

抛出一个 Laravel Eloquent 异常

接下来我们故意创建一个内置的错误来引发一个异常。因此使用 findOrFail() 方法从模型中提取不存在的记录。
使用 laravel 自带的 User 模型,执行迁移命令创建数据表

添加一个路由和控制器 app/Http/routes.php

Route::get('/user', [
    'uses' => 'SampleController@findUser',
    'as' => 'user'
]);

App/Http/Controllers/SampleController.php

    /**
     * Return the first user in the users table
     *
     * @return Array    User details
     */
    public function findUser()
    {
        $user = User::firstOrFail();
        return $user->toArray();
    }

浏览器访问,一个 ModelNotFoundException 的异常

image
image

捕获自定义异常

MODELNOTFOUNDEXCEPTION

有了这个异常,我们现在可以添加一个自定义处理程序,返回我们自己的错误消息。

如果异常是 ModelNotFoundExceptionNotFoundHttpException 之一,我们将修改 app/Exceptions/Handler.php中的 render 方法,以返回 ajax 请求的 json 响应或正常请求的视图。如果两者都不是,就让 laravel 自己处理异常

/**
     * 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)
    {
        //check if exception is an instance of ModelNotFoundException.
        if ($e instanceof ModelNotFoundException) {
            // ajax 404 json feedback
            if ($request->ajax()) {
                return response()->json(['error' => 'Not Found'], 404);
            }

            // normal 404 view page feedback
            return response()->view('errors.missing', [], 404);
        }

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

resources/views/errors 中添加一个 404.blade.php 文件包含反馈信息。

<!DOCTYPE html>
<html>
<head>
    <title>User not found.</title>
</head>
<body>
    <p>You broke the balance of the internet</p>
</body>
</html>

刷新页面我们可以看到该错误状态消息

image
image

NOTFOUNDHTTPEXCEPTION

当用户访问未定义的 URL(例如/foo/bar/randomstring),会抛出 NotFoundHttpException 异常。要处理这个异常, 我们将在我们之前修改的 render 方法中添加第二个条件,并返回消息到 resources/view/errors/missing.blade.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)
    {
        //check if exception is an instance of ModelNotFoundException.
        //or NotFoundHttpException
        if ($e instanceof ModelNotFoundException or $e instanceof NotFoundHttpException) {
            // ajax 404 json feedback
            if ($request->ajax()) {
                return response()->json(['error' => 'Not Found'], 404);
            }

            // normal 404 view page feedback
            return response()->view('errors.missing', [], 404);
        }

        return parent::render($request, $e);
    }
    
    /**
     *
     * 对于HttpException 这样写,统一性更好
     */
     
      if($this->isHttpException($e))
        {
            if (view()->exists('errors.'.$e->getStatusCode()))
            {
                return response()->view('errors.'.$e->getStatusCode(), [],               $e->getStatusCode());
            }
        }
        return parent::render($request, $e);

使用 Laravel Abort()方法

调用 abort() 生成404错误页面,该方法接收可选的响应消息

abort(404, 'The resource you are looking for could not be found');

它将检查相应的 resources/view/errors/404.blade.php 页面,并将404状态码的 HTTP 响应提供给浏览器,这同样适用于401和500错误状态码。

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 122,057评论 17 134
  • 所有示例基于Laravel 5.1.39 (LTS) 今天天气不错,我们来说说表单验证。 Controller中做...
    该叶无法找到阅读 22,249评论 15 23
  • (转自网络)画家小传 马蒂斯(1869~1954),西方野兽主义艺术风格的创始人和领导者。出生于法国北部的开始学画...
    salen小伦阅读 253评论 0 2
  • 漫步于幽幽小径,心中有淡淡愁绪,三两心事却无人可诉。只听得脚底下枯叶沙沙作响。晚霞映照在苍穹一侧,余晖透过错落...
    朝九迹涯阅读 53评论 0 3
  • 1.HR领域专家/顾问 2.心理咨询师 3.职业规划师 4.自由撰稿人/签约作家 5.电台播音主持 6.育儿达人/...
    小M的日常阅读 52评论 0 0