1. 程式人生 > >Laravel 中的異常處理

Laravel 中的異常處理

這篇文章裡,我們將研究 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 檔案:

<?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

<?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: <b>{{ $exception->getMessage() }}</b>

要想上面的程式碼執行,我們還需要修改 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 來測試我們寫的自定義異常類:

<?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', '[email protected]');

然後訪問 http://your-laravel-site.com/exception/index , 最終應當輸出 errors.custom 檢視。

所以以上就是 Laravel 處理異常的過程,希望你會喜歡。

本文翻譯自,部分有所改動。
原文連結:https://code.tutsplus.com/tutorials/exception-handling-in-laravel--cms-30210