【Laravel】errorのカスタム画面の作成手順

# はじめに
エラー画面に、「トップページへ」などのリンクを貼りたい。
そのために、エラー画面を編集したい。
↓
Laravelの場合、エラー画面を編集するのではなく、
エラー画面を自作でカスタムする必要がある。

### デフォルトのエラー画面
![スクリーンショット 2025-04-18 19.04.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3726068/cd672e32-fc70-49a5-85cd-0c75d9ae6804.png)

### カスタムのエラー画面
![スクリーンショット 2025-04-18 19.51.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3726068/954de929-7182-4242-8507-4bf1810e2845.png)



# エラーページの作成手順
## ① ディレクトリ作成(なければ)
```bash
mkdir resources/views/errors
```


## ② Bladeファイル作成(404例 / コンポーネント)
```bash
# --- 404の個別ページ
# touch = 空ファイル作成
touch resources/views/errors/404.blade.php

# --- エラー画面の共通コンポーネント
# mkdir -p = ディレクトリ(フォルダ)を階層ごとまとめて作成
mkdir -p resources/views/components/errors
touch resources/views/components/errors/error-page.blade.php
```


## ③ カスタム画面の中身
### 代表的なエラー画面一覧（ステータスコード別）
まずは図で解説して、その後にコードを記載します。
| ステータスコード | エラー名 | 意味・用途例 |
|:-----------|:----------- |:------------ |
| 400 | Bad Request | リクエストに誤りがあります。もう一度お試しください。 |
| 401 | Unauthorized | ログインが必要です。認証後に再度お試しください。 |
| 403 | Forbidden | このページにはアクセスできません。権限をご確認ください |
| 404 | Not Found | お探しのページは見つかりませんでした。URLをご確認ください。 |
| 419 | Page Expired | セッションの有効期限が切れました。ページを再読み込みしてください。 |
| 422 | Unprocessable Entity | 入力内容に不備があります。もう一度ご確認ください。 |
| 429 | Too Many Requests | アクセスが集中しています。しばらくしてから再度お試しください。 |
| 500 | Internal Server Error | サーバーでエラーが発生しました。ご迷惑をおかけしております。 |
| 503 | Service Unavailable | 現在サービスが一時的にご利用いただけません。時間を置いて再度お試しください。 |


### 400
```resources/views/errors/400.blade.php
<x-errors.error-page 
    :code="400" 
    title="Bad Request" 
    message="リクエストに不備があるようです。<br>もう一度お試しください。" 
/>
```

### 401
```resources/views/errors/401.blade.php
<x-errors.error-page 
    :code="401" 
    title="Unauthorized" 
    message="ログインが必要です。<br>認証後に再度お試しください。" 
/>
```

### 403
```resources/views/errors/403.blade.php
<x-errors.error-page 
    :code="403" 
    title="Forbidden" 
    message="このページにはアクセスできません。" 
/>
```

### 404
```resources/views/errors/404.blade.php
<x-errors.error-page 
    :code="404" 
    title="Not Found" 
    message="お探しのページは見つかりませんでした。" 
/>
```

### 419
```resources/views/errors/419.blade.php
<x-errors.error-page 
    :code="419" 
    title="Page Expired" 
    message="セッションの有効期限が切れました。<br>ページを再読み込みしてください。" 
/>
```

### 422
```resources/views/errors/422.blade.php
<x-errors.error-page 
    :code="422" 
    title="Unprocessable Entity" 
    message="入力内容に不備があります。<br>もう一度ご確認ください。" 
/>
```

### 429
```resources/views/errors/429.blade.php
<x-errors.error-page 
    :code="429" 
    title="Too Many Requests" 
    message="アクセスが集中しています。<br>しばらくしてから再度お試しください。" 
/>
```

### 500
```resources/views/errors/500.blade.php
<x-errors.error-page 
    :code="500" 
    title="Internal Server Error" 
    message="サーバーエラーが発生しました。<br>ご迷惑をおかけしております。" 
/>
```

### 503
```resources/views/errors/503.blade.php
<x-errors.error-page 
    :code="503" 
    title="Service Unavailable" 
    message="現在メンテナンス中です。<br>時間を置いて再度お試しください。" 
/>
```


## ④ コンポーネントの中身
```resources/views/components/errors/error-page.blade.php
<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{ $code }} | {{ $title }}</title>
    @vite('resources/css/app.css')
</head>

<body class="bg-gray-100 text-gray-800 flex flex-col min-h-screen overflow-y-scroll">

    {{-- ヘッダー --}}
    <header class="bg-gray-200 border-b border-gray-100">
      <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
          <div class="flex justify-between h-16">
              <div class="flex">
                  <!-- Logo -->
                  <div class="shrink-0 flex items-center">
                      <a href="{{ route('XXX.index') }}">
                          <x-application-logo class="block h-9 w-auto fill-current text-gray-800" />
                      </a>
                  </div>
              </div>
          </div>
      </div>
    </header>

    {{-- メイン --}}
    <main class="flex-grow flex flex-col justify-center items-center text-center px-4">
        <h2 class="text-xl font-bold mb-2">{{ $code }} | {{ $title }}</h2>
        <p class="mb-6">{!! $message !!}</p>
        <button type="submit"
            class="bg-indigo-500 text-white py-2 px-4 rounded-md hover:bg-indigo-600 transition text-lg">
                <a href="{{ route('XXX.index') }}">トップページはこちら</a>
        </button>
    </main>

    {{-- フッター --}}
    <footer class="shadow bg-gray-200 py-4 text-center text-sm text-gray-500">
        © {{ date('Y') }} {{ config('app.name') }} All rights reserved
    </footer>

</body>
</html>
```


## ⑤ エラー画面の確認
```routes/web.php
use Illuminate\Support\Facades\Route;

// エラー画面の確認テスト
// 400 Bad Request
Route::get('/force-400', function () { abort(400, 'Bad Request Test'); });
// 401 Unauthorized
Route::get('/force-401', function () { abort(401, 'Unauthorized Test'); });
// 403 Forbidden
Route::get('/force-403', function () { abort(403, 'Forbidden Test'); });
// 404 Not Found
Route::get('/force-404', function () { abort(404, 'Not Found Test'); });
// 419 Page Expired
Route::get('/force-419', function () { abort(419, 'Page Expired Test'); });
// 422 Unprocessable Entity
Route::get('/force-422', function () { abort(422, 'Unprocessable Entity Test'); });
// 429 Too Many Requests
Route::get('/force-429', function () { abort(429, 'Too Many Requests Test'); });
// 500 Internal Server Error（throwで例外を発生させる）
Route::get('/force-500', function () { throw new \Exception('Internal Server Error Test'); });
// 503 Service Unavailable
Route::get('/force-503', function () { abort(503, 'Service Unavailable Test'); });
```
↓

URLを直接webページに打ち込む
```
# 開発環境の例
http://127.0.0.1:8000/force-404

# 本番環境の例
http://(自分のドメイン.com)/force-404
```

↓ これになるはず

![スクリーンショット 2025-04-18 19.51.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3726068/954de929-7182-4242-8507-4bf1810e2845.png)