这篇文章里,我们将研究 Laravel 框架中最重要也最少被讨论的功能 —— 异常处理。
Laravel 自带了一个异常处理类,它能够让你以简单、优雅的方式 report 和 render 异常。
文章的前半部分,我们将研究异常处理类(exception handler)提供的默认配置,然后研究异常处理类,并借此理解 Laravel 框架处理异常的过程。
文章的后半部分,我们将创建一个自定义的异常处理类,用于捕获自定义的异常。
异常处理类
首先,我们看一下与异常相关的配置,打开 config/app.php 文件,找到下面这个片段:
...
...
/*
|--------------------------------------------------------------------------
| Application Debug Mode
|--------------------------------------------------------------------------
|
| When your application is in debug mode, detailed error messages with
| stack traces will be shown on every error that occurs within your
| application. If disabled, a simple generic error page is shown.
|
*/
'debug' => env('APP_DEBUG', false),
...
...
正如注释中所说,debug 设置为 true 时,会显示详细的调试错误信息,设置为 false 时,只显示简单的错误信息。这个变量的默认值是通过 .env 文件中的 APP_DEBUG 环境变量设置的。
在开发环境下,你应该将其设置为 true,这样开发时更容易发现错误并修复它们。在生产环境下应该设置为 false,只显示简单的信息。
除了显示错误,你还可以将错误记录到日志文件中。打开配置文件 config/app.php,找到下面这行代码:
...
...
'log' => env('APP_LOG', 'single'),
'log_level' => env('APP_LOG_LEVEL', 'debug'),
...
...
日志文件默认路径为:storage/logs/laravel.log,大部分场景下它已经够用了。APP_LOG_LEVEL决定了错误日志被记录的级别。
上面就是关于异常和日志相关的配置的基本介绍。
然后,我们看一下 Laravel 自带的默认异常处理类。打开 app/Exceptions/Handler.php 文件:
namespace App\Exceptions;
use Exception;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
class Handler extends ExceptionHandler
{
/**
* A list of the exception types that should not be reported.
*
* @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\Session\TokenMismatchException::class,
\Illuminate\Validation\ValidationException::class,
];
/**
* Report or log an exception.
*
* This is a great spot to send exceptions to Sentry, Bugsnag, etc.
*
* @param \Exception $exception
* @return void
*/
public function report(Exception $exception)
{
parent::report($exception);
}
/**
* Render an exception into an HTTP response.
*
* @param \Illuminate\Http\Request $request
* @param \Exception $exception
* @return \Illuminate\Http\Response
*/
public function render($request, Exception $exception)
{
return parent::render($request, $exception);
}
/**
* Convert an authentication exception into an unauthenticated response.
*
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Auth\AuthenticationException $exception
* @return \Illuminate\Http\Response
*/
protected function unauthenticated($request, AuthenticationException $exception)
{
if ($request->expectsJson()) {
return response()->json(['error' => 'Unauthenticated.'], 401);
}
return redirect()->guest(route('login'));
}
}
这里有两个重要的方法:report() 和 render()。
report() 方法用于将异常报告给外部服务或者记录日志,默认情况下,将异常传递给记录异常的基类。注意对于添加到 dontReport 属性数组中的异常类,则不会被报告(执行此方法)。
render() 方法负责将给定的异常转换为将被发送回浏览器的 HTTP 响应。默认情况下,异常将传递给为你生成响应的基类。你可以在这里针对不同的异常,自定义相应的响应。
最后,提供了一个 unauthenticated() 方法用于处理 AuthenticationException 异常,能够让你决定未认证时用户能够看到的信息。
自定义异常
下面我们创建一个自定义异常类来处理 CustomException 类型的异常。这个自定义异常类背后的原则同时支持异常管理和自定义异常信息的输出。
我们创建一个异常类文件app/Exceptions/CustomException.php:
namespace App\Exceptions;
use Exception;
class CustomException extends Exception
{
/**
* Report the exception.
*
* @return void
*/
public function report()
{
}
/**
* Render the exception into an HTTP response.
*
* @param \Illuminate\Http\Request
* @return \Illuminate\Http\Response
*/
public function render($request)
{
return response()->view(
'errors.custom',
array(
'exception' => $this
)
);
}
}
注意到,CustomException 扩展自 Exception 类。出于演示目的,我们只讨论 render() 方法,当然你也可以自定义 report() 方法。
上面的 render() 中,我们将显示 errors.custom 页面给用户。通过这种方式,你可以为自己的异常自定义页面输出。
当然,我们还要创建一个相关联的视图文件 resources/views/errors/custom.blade.php:
Exception details: {{ $exception->getMessage() }}
要想上面的代码执行,我们还需要修改 app/Exceptions/Handler.php 中的 render() 方法:
...
...
/**
* Render an exception into an HTTP response.
*
* @param \Illuminate\Http\Request $request
* @param \Exception $exception
* @return \Illuminate\Http\Response
*/
public function render($request, Exception $exception)
{
if ($exception instanceof \App\Exceptions\CustomException) {
return $exception->render($request);
}
return parent::render($request, $exception);
}
...
...
在这里,我们先检查异常类型,然后调用我们自己的异常的 render() 方法从而实现输出。
所有到此所有的就介绍完了。
让我们继续,创建一个控制器 app/Http/Controllers/ExceptionController.php 来测试我们写的自定义异常类:
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
class ExceptionController extends Controller
{
public function index()
{
// something went wrong and you want to throw CustomException
throw new \App\Exceptions\CustomException('Something Went Wrong.');
}
}
然后在 routes/web.php 中添加一个路由:
// Exception routes
Route::get('exception/index', 'ExceptionController@index');
所以以上就是 Laravel 处理异常的过程,希望你会喜欢。