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


1. 419 Page Expiredの概要
Laravelアプリケーションでフォームを送信すると、419 Page Expiredエラーが発生することがあります。このエラーは、主にCSRFトークンの不在が原因で発生します。CSRFトークンは、クロスサイトリクエストフォージェリ(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>

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 serve
でhttp://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>

この状態でフォームを送信すると、次のように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トークンをリクエストヘッダーに含めています。alertでjsonの内容を出力することができました。
5. まとめ
419 Page Expiredエラーは、主にCSRFトークンの不在が原因で発生します。フォームに@csrf
ディレクティブを追加し、セッション管理を適切に行うことで、このエラーを防ぐことができます。また、非同期通信を使用する場合は、Fetch APIを使用してリクエストヘッダーにCSRFトークンを含める必要があります。

