---
# System prepended metadata

title: 錯誤處理
tags: [laravel]

---

---
tags: laravel
---
# 錯誤處理
![](https://i.imgur.com/dGcN9AI.jpg)

## 簡介

當你開始一個新的 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`