Webアプリケーションを構築する際には、ユーザーエクスペリエンスを損なわないエラーハンドリングが不可欠です。
Laravel 11とInertia.jsを組み合わせて、カスタマイズ可能なエラーページを作成する方法を解説します。
目次
技術構成
- Laravel11
- Inertiajs (Vuejs)
- tailwindcss
- sail
- docker
実装すること
Laravelデフォルトのエラーページではなく、自分でカスタマイズしたページを表示する。
なぜエラーページを自作するのか?
HTTPステータスコード、特にユーザーの操作に直接関連するもの(例えば419 'Page Expired')に対して、デフォルトのエラーメッセージではなく、より具体的なユーザーガイダンスを提供することが望ましい場合があるからです。
非エンジニアが、アプリケーションを操作していて、いきなりLaravelのデフォルトのエラーページが表示されたらびっくりしちゃうと思います。
公式ドキュメントを読む
公式ドキュメントには以下のような文章が書かれていました。
Rarely, you may need to customize the entire HTTP response rendered by Laravel's exception handler. To accomplish this, you may register a response customization closure using the
respond
method:https://laravel.com/docs/11.x/errors#customizing-the-exception-responseuse Symfony\Component\HttpFoundation\Response; ->withExceptions(function (Exceptions $exceptions) { $exceptions->respond(function (Response $response) { if ($response->getStatusCode() === 419) { return back()->with([ 'message' => 'The page expired, please try again.', ]); } return $response; }); })
respondメソッドを使用して、レスポンスのカスタマイズクロージャーを登録するという内容でした。
次に、実際に処理を書いてみます。
Laravel11とInertiajsでカスタムエラーページを作成する方法解説
今まではapp/Exceptions/Handler.php
にエラーハンドリングの処理は書いていましたが、Laravel11ではbootstrap/app.php
にコードを書く必要がありそうです。
->withExceptions
ブロックの中に、以下を足します。
<?php
use Symfony\Component\HttpFoundation\Response;
use Inertia\Inertia;
....省略
->withExceptions(function (Exceptions $exceptions) {
$exceptions->respond(function (Response $response) {
if (!app()->environment(['local', 'testing']) && in_array($response->getStatusCode(), [404, 500, 403, 503])) {
return Inertia::render('Error', [
'status' => $response->getStatusCode(),
]);
}
return $response;
});
})
次に、Vueファイルも作成しましょう。
/resources/js/Pages/Error.vue
を作成し、以下みたいな感じで書きます。
<script setup>
import ApplicationLogo from "@/Components/ApplicationLogo.vue";
import { computed } from "vue";
import PrimaryButton from "@/Components/PrimaryButton.vue";
import { Link, usePage, Head } from "@inertiajs/vue3";
const props = defineProps({ status: Number });
const title = computed(() => {
return {
503: "503 SERVICE UNAVAILABLE",
500: "500 SERVER ERROR",
404: "404 NOT FOUND",
403: "403 FORBIDDEN",
}[props.status];
});
const description = computed(() => {
return {
503: "申し訳ございませんが、現在メンテナンス中です。しばらくお待ちください。",
500: "サーバーに異常が発生しました。",
404: "お探しのページは見つかりませんでした。",
403: "このページへのアクセスは禁止されています。",
}[props.status];
});
</script>
<template>
<Head :title="description"/>
<header
class="flex flex-wrap justify-center md:flex-nowrap z-[1000] w-full py-4 fixed top-0 left-0 bg-white bg-opacity-60 backdrop-blur-sm"
>
<Link
href="/"
class="flex-none rounded-xl text-xl inline-block font-semibold focus:outline-none focus:opacity-80"
>
<ApplicationLogo
class="md:w-48 md:h-8 w-30 h-6 fill-current text-gray-500"
/>
</Link>
</header>
<div class="text-zinc-800 mt-36 mb-32 px-6">
<h1 class="font-medium sm:text-7xl text-4xl text-center">
{{ title }}
</h1>
<p class="text-center font-medium mt-3 sm:text-md text-sm">
{{ description }}
</p>
<div class="flex mt-8 justify-center">
<Link :href="'/'">
<PrimaryButton>トップに戻る</PrimaryButton>
</Link>
</div>
</div>
</template>
コードの説明
bootstrap/app.php
app()->environment(['local', 'testing'])
を使用して、現在のアプリケーションがローカルまたはテスト環境にあるかどうかを確認します。これがfalse
の場合(つまり本番環境の場合)、指定されたステータスコード(404, 500, 403, 503)のいずれかであるかをチェックします。- 上記の条件に一致する場合、
Inertia::render
を使ってError
コンポーネントをレンダリングします。この時、エラーステータスコードをstatus
プロパティとしてコンポーネントに渡して、適切なエラー情報を表示します。
resources/js/Pages/Error.vue
defineProps
を使用して、親コンポーネントから受け取るstatus
プロパティ(HTTPステータスコード)を定義しています。title
とdescription
は計算プロパティで、受け取ったステータスコードに応じてエラータイトルと説明文を返します。
これで、404, 500, 403, 503
の時にエラーページを無事表示することができました 🎉
まだデフォルトのエラーページが表示される方は、本番環境設定になっているかやエラー内容を確認してみてください。