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错误状态码。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,743评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,296评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,285评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,485评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,581评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,821评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,960评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,719评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,186评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,516评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,650评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,936评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,757评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,991评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,370评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,527评论 2 349

推荐阅读更多精彩内容

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