错误和异常是处理程序开发中不可回避的议题,在本地开发中我们往往希望能捕获程序抛出的异常并将其显示打印出来,以便直观的知道程序在哪里出了问题并予以解决,而在线上环境我们不希望将程序错误或异常显示在浏览器中(出于安全考虑),这个时候我们仍然要捕获异常,只不过不是显示到浏览器中,而是记录到日志中,方便日后排查问题。
Laravel当然支持PHP原生的错误和异常处理,但是在此基础上进行了一些封装处理,从而更方便在不同开发环境切换以及对错误和异常的处理。
我们可以在config/app.php
文件中通过debug
配置项来决定是否开启调试模式,其默认配置如下:
'debug' => env('APP_DEBUG', false),
当然真正的配置位于项目根目录下的.env
文件,如果其值为true
,则如果程序抛出异常会在页面中显示错误异常信息。
Laravel应用中所有的异常都通过App\Exceptions\Handler
进行处理,下面我们先简单分析下给异常处理器类的属性和方法:
protected $dontReport = [ HttpException::class, ModelNotFoundException::class, ];
$dontReport
属性定义了不会被记录到日志的异常,比如默认HTTP异常和ModelNotFound
异常都不会记录下来,而是直接在浏览器中打印异常信息。
public function report(Exception $e) { return parent::report($e); }
report
方法会调用父级的report
方法将异常信息记录到日志中(关于日志我们将在下一节讲)。
public function render($request, Exception $e) { if ($e instanceof ModelNotFoundException) { $e = new NotFoundHttpException($e->getMessage(), $e); } return parent::render($request, $e); }
render
方法会将异常信息渲染到HTTP响应中,从而让我们在开发过程中直观地浏览器中查看错误信息以便找到问题所在。
下面我们来简单测试下ModelNotFoundException
,顾名思义,在使用Eloquent ORM进行查询时对应模型实例在数据库中没有找到会抛出该异常。
我们照例在TestController的index方法中编写测试代码如下:
$user = User::findOrFail(100); dd($user);
然后在浏览器中访问http://laravel.app:8000/test
,页面会打印出错误信息:
由于ModelNotFoundException
在$dontReport
属性数组中,因而不会记录到日志中(NotFoundHttpException
是HttpException
的子类,所以也不会被记录到日志),接下来我们测试如下代码:
$num = 1/0;
再次访问http://laravel.app:8000/test
,同样,页面会打印错误信息:
除此之外,在错误日志storage/logs/laravel.log
中也能看到写入进来的错误信息:
[2015-11-08 21:21:47] local.ERROR: exception 'ErrorException' with message 'Division by zero' in /vagrant/laravelapp/app/Http/Controllers/TestController.php:389 Stack trace: ...
而且,通过这些错误信息,既可以知道出错原因,也知道出错代码在程序中的位置,可以大大节省我们排查错误原因的时间,提高编程效率。
日常开发中,我们经常会遇到404、500之类的HTTP错误码,表示页面未找到或者服务器错误之类的问题,Laravel为我们提供了单独的方法来处理这些错误异常:
我们使用abort
方法来简单抛出HTTP错误码异常,如果页面没找到或者数据不存在,我们使用如下方法抛出404异常:
abort(404);
如果是服务器授权认证失败,我们可以通过如下方式抛出403异常,当然,还可以传入错误信息到abort
方法:
abort(403,'对不起,您无权访问该页面!');
对于抛出403异常的页面,默认显示如下:
这样的页面显然不能放到线上环境,那又应该如何为HTTP异常创建自定义视图呢?别担心,Laravel已经为我们做了周全的处理:
如果要创建诸如404、403、500这样的HTTP异常自定义视图,只需在resources/views/errors
目录创建与错误码对应的页面视图文件即可。比如要定义上述403异常自定义视图,可以创建resources/views/errors/403.blade.php
文件,现在我们简单定义其内容如下:
{{$exception->getMessage()}}
这样再次测试403异常页面,显示如下:
对不起,您无权访问该页面!
没错,就是403.blade.php
文件中的内容,是不是很方便?
注:
abort
方法底层还是抛出相应异常,404错误抛出NotFoundHttpException
,其他HTTP错误抛出HttpException
。