LaravelのPOST Requests時に“419 Page Expired” Error:原因と解決策

はるか
はるか
419 Page Expired。明日に任せるか。

ふゅか
ふゅか
ちょっと待って!それってCSRFトークン関連のエラーだよ!

1. 419 Page Expiredの概要

Laravelアプリケーションでフォームを送信すると、419 Page Expiredエラーが発生することがあります。このエラーは、主にCSRFトークンの不在が原因で発生します。CSRFトークンは、クロスサイトリクエストフォージェリ(CSRF)攻撃を防ぐために使用され、ユーザーが送信するすべてのフォームに含める必要があります。

2. エラーの原因

419 Page Expiredエラーが発生する一般的な原因は、以下の通りです。

  1. フォームにCSRFトークンが含まれていない。
  2. 非同期通信の時に、csrfトークンが含まれていない。

はるか
はるか
CSRFトークンを書けば動く。

3. 解決策

419 Page Expiredを解決するための具体的な手順は以下の通りです。

3.1. フォームにCSRFトークンを含める

Laravelでは、フォームにCSRFトークンを簡単に含めるためのディレクティブが用意されています。フォームタグの内部に@csrfディレクティブを追加します。

<form action="/your-route" method="POST">
    @csrf
    <!-- フォームフィールド -->
    <button type="submit">送信</button>
</form>
ふゅか
ふゅか
まず、フォームにCSRFトークンがない場合が多いわ。これを防ぐためには、@csrfディレクティブを使うのが基本よ。

4. エラーの検証と修正

419 Page Expiredを検証し、修正するための手順を具体的に示します。次の画像のような419 Page Expiredを表示して、そのエラーを解消します。

4.1. 検証環境

  • PHP 8.1.25
  • Laravel 10.48.12
  • Windows 11

4.2. コントローラーの作成

まず、フォームデータを処理するためのコントローラーを作成します。例として、ContactControllerを作成します。

php artisan make:controller ContactController

作成したコントローラーに以下のメソッドを追加します。

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class ContactController extends Controller
{
    public function index()
    {
        return view('contact');
    }

    public function store(Request $request)
    {
        // フォームデータの処理
        return response()->json(['message' => 'Form submitted successfully!']);
    }
}

4.3. ルーティング

次に、ルートを設定します。web.phpファイルに以下のルートを追加します。

use App\Http\Controllers\ContactController;

Route::get('/contact', [ContactController::class, 'index'])->name('contact.index');
Route::post('/contact', [ContactController::class, 'store'])->name('contact.store');

4.4. viewの作成

まず、resources/views/contact.blade.php にフォームを作成し、CSRFトークンを含めない状態で送信してみます。以下のコードは、CSRFトークンを含まないフォームの例です。

<!DOCTYPE html>
<html>
<head>
    <title>Contact Form</title>
</head>
<body>
    <form action="{{ route('contact.store') }}" method="POST">
        <!-- CSRFトークンがない -->
        <input type="text" name="name" placeholder="Your Name">
        <button type="submit">送信</button>
    </form>
</body>
</html>

4.5. エラーの原因と修正方法

php artisan servehttp://127.0.0.1:8000/contactに移動します。
この状態でフォームを送信すると、次の画像のように419 Page Expiredエラーが発生します。

これを修正するために、resources/views/contact.blade.php のフォームタグの内部に@csrfディレクティブを追加します。


<!DOCTYPE html>
<html>
<head>
    <title>Contact Form</title>
</head>
<body>
    <form action="{{ route('contact.store') }}" method="POST">
        @csrf
        <input type="text" name="name" placeholder="Your Name">
        <button type="submit">送信</button>
    </form>
</body>
</html>
ふゅか
ふゅか
これでCSRFトークンが追加されたので、エラーは解消されるはずよ。

この状態でフォームを送信すると、次のようにjsonからフォームの送信に成功したというメッセージを受け取ることができます。

4.6. 非同期通信の例

次に、非同期通信を使用する場合の例を示します。JavaScriptを使用してフォームデータを送信する場合も、CSRFトークンを含める必要があります。以下は、Fetch APIを使用してフォームを送信する例です。

<!DOCTYPE html>
<html>
<head>
    <title>Contact Form</title>
    <meta name="csrf-token" content="{{ csrf_token() }}">
</head>
<body>
    <form id="contactForm">
        <input type="text" name="name" placeholder="Your Name">
        <button type="submit">送信</button>
    </form>

    <script>
        document.addEventListener('DOMContentLoaded', function() {
            document.getElementById('contactForm').addEventListener('submit', function(event) {
                event.preventDefault();

                const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
                const formData = new FormData(this);

                fetch('{{ route('contact.store') }}', {
                    method: 'POST',
                    headers: {
                        'X-CSRF-TOKEN': csrfToken,
                        'Accept': 'application/json'
                    },
                    body: formData
                })
                .then(response => response.json())
                .then(data => {
                    alert(data.message);
                })
                .catch(error => {
                    alert('Submission failed: ' + error);
                });
            });
        });
    </script>
</body>
</html>

はるか
はるか
fetch APIの場合も、CSRFトークンをヘッダーに含めるのがポイント。

この例では、Fetch APIを使用してフォームデータを送信し、CSRFトークンをリクエストヘッダーに含めています。alertでjsonの内容を出力することができました。

5. まとめ

419 Page Expiredエラーは、主にCSRFトークンの不在が原因で発生します。フォームに@csrfディレクティブを追加し、セッション管理を適切に行うことで、このエラーを防ぐことができます。また、非同期通信を使用する場合は、Fetch APIを使用してリクエストヘッダーにCSRFトークンを含める必要があります。

ふゅか
ふゅか
まとめると、CSRFトークンの追加はエラー回避に必須ってことね。
はるか
はるか
うん、これで安全にフォーム送信ができる。
PR