--- tags: laravel --- # 錯誤處理  ## 簡介 當你開始一個新的 Laravel 項目時,它已經配置了錯誤和異常處理機制。 App\Exceptions\Handler 類別用於記錄應用觸發的所有異常,然後將其呈現給用戶。我們將在本章節深入討論這個類別 ## 設定 config/app.php 設定檔案中的 debug 選項決定了對於一個錯誤實際上將顯示多少訊息給用戶。預設情況下,該選項的設置將按照在 .env 檔案中的 APP_DEBUG 環境變數的值 對於本地開發,你應該將 APP_DEBUG 環境變數的值設置為 true。在正式環境中,該值應始終為 false。如果在正式環境中將該值設置為 true,可能會將敏感設定值暴露給應用的用戶 ## 異常處理 ### 報告異常 所有異常都是由 App\Exceptions\Handler 類別處理。此類包含一個 register() ,可以在其中註冊自定義異常報告程序和渲染器回呼。本文將詳細說明每個概念。異常報告用於記錄異常或將其發送到如 Flare、Bugsnag 或 Sentry 等外部服務。預設情況下,將根據你的日誌配置來記錄異常。不過你可以用自己喜歡的方式來記錄異常 例如,如果您需要使用不同的方式來報告不同的異常,可以使用 reportable() 來註冊一個 Closure,當需要報告指定的異常的時候便會執行它。 Laravel 將通過檢查 Closure 的型別提示來判斷 Closure 報告的異常類型 ``` use App\Exceptions\InvalidOrderException; /** * Register the exception handling callbacks for the application. * * @return void */ public function register() { $this->reportable(function (InvalidOrderException $e) { // }); } ``` 當使用 reportable() 註冊一個自定義異常報告回呼函式時, Laravel 依然會使用預設的日誌配置記錄下應用異常。 如果您想要在預設的日誌堆疊中停止這個行為,可以在定義報告回呼時使用 stop() ``` $this->reportable(function (InvalidOrderException $e) { // })->stop(); $this->reportable(function (InvalidOrderException $e) { return false; }); ``` > 技巧: > > 要為指定的異常自定義異常報告,可以使用可報告異常 #### 全域日誌 Context 在可用的情況下, Laravel 會自動將當前用戶的編號作為資料添加到每一條異常日誌資料中。你可以通過複寫 App\Exceptions\Handler 類別中的 context() 來定義您自己的全域 Context(環境變數),此後每一條異常日誌訊息都將包含這個訊息 ``` /** * Get the default context variables for logging. * * @return array */ protected function context() { return array_merge(parent::context(), [ 'foo' => 'bar', ]); } ``` #### reporter 幫助函式 有時你可能需要報告異常,但不終止當前請求的處理。 report() 幫助函數允許你在不渲染錯誤頁面給用戶的情況下快速報告異常: ``` public function isValid($value) { try { // Validate the value... } catch (Throwable $e) { report($e); return false; } } ``` ### 按類型忽略異常 當建立應用時,常會有些類型的異常是你想要忽略掉而不需要報告的。應用的異常處理器的 $dontReport 屬性包含了一個不會被日誌記錄的異常類型的陣列,它預設是一個空陣列,任何類別被加到這個陣列後將不會被回報。比方說由 404 錯誤導致的錯誤就不會被寫到日誌中,你可以根據需要添加其他異常類型到該陣列中 ``` use App\Exceptions\InvalidOrderException; /** * A list of the exception types that should not be reported. * * @var array */ protected $dontReport = [ InvalidOrderException::class, ]; ``` 在背後, Laravel 已經為你忽略了一些類型的錯誤,比方說 404 的 HTTP not found 錯誤,或者是由無效的 CSRF tokens 所造成的 419 HTTP 回應等 ### 渲染異常 預設情況下, Laravel 異常處理器會自動為你轉換異常為 HTTP 回應。你當然也可以在異常處理器的 renderable() 中註冊一個特定類型的異常的自定義渲染 Closure 來實現。 傳給 renderable() 的 Closure 應該要回傳一個 Illuminate\Http\Response 實例,它將會經由 response() 來生成。 Laravel 將會根據 Closure 的型別提示來確定異常的類別: ``` use App\Exceptions\InvalidOrderException; /** * Register the exception handling callbacks for the application. * * @return void */ public function register() { $this->renderable(function (InvalidOrderException $e, $request) { return response()->view('errors.invalid-order', [], 500); }); } ``` ### Reportable & Renderable 異常 除了在異常處理器的 report 和 render 方法中檢查異常類型外,你也可以直接在自定義異常中定義 report 和 render 方法。當定義了這些方法之後它們將被框架自動呼叫 ``` <?php namespace App\Exceptions; use Exception; class InvalidOrderException extends Exception { /** * Report the exception. * * @return void */ public function report() { // } /** * Render the exception into an HTTP response. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function render($request) { return response(...); } } ``` 如果您的異常包含了僅在滿足某些條件時才報告的自定義報告邏輯,您可能需要指示 Laravel 在某些狀況下只使用預設的異常處理配置去報告它。你可以在異常的 report() 中回傳 false 來達成: ``` /** * Report the exception. * * @return bool|void */ public function report() { // Determine if the exception needs custom reporting... return false; } ``` > 技巧: > > 你可以通過型別提示傳遞任意的依賴到 report() 中,它們將被 Laravel 的服務容器自動注入到方法中 ## HTTP 異常 某些錯誤碼描述了服務器的 HTTP 錯誤原因。例如,錯誤404代表「頁面未找到」,錯誤401代表「未經授權的錯誤」甚至是開發者造成的 500 內部錯誤。要在應用的任何地方生成這樣的回應,可以使用 abort() 幫助函式 `abort(404);` ### 自定義 HTTP 錯誤頁面 Laravel 創建了可以輕鬆顯示各種 HTTP 狀態碼的自定義錯誤頁面。例如如果您想要自定義 HTTP 狀態碼為 404 的錯誤頁面,您只需創建 resources/views/errors/404.blade.php 檔案。該檔案用於應用產生的所有 404 錯誤。errors資料夾中的視圖名稱應為它們所對應的 HTTP 狀態碼。由 abort() 引發的 HttpException 實例將作為 $exception 變數傳遞給視圖: `<h2>{{ $exception->getMessage() }}</h2>` 你可以使用 vendor:publish 這一個 Artisan 命令來發布 Laravel 錯誤頁面模板到專案中。一旦你發布了模板,你就可以根據需要來自定義它們 `php artisan vendor:publish --tag=laravel-errors`
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up