Laravel のリダイレクトが意図せず発火し続けた原因と、Docker+ブラウザキャッシュの落とし穴
📌 はじめに
Laravel で「過去の西暦なら来年ページにリダイレクトする」というシンプルな処理を実装していたところ、
想定していない /2025 → /2026 リダイレクトが永久に発生するという問題に遭遇しました。
調査の結果、
- ルートでも
- コントローラの中でも
-
dd()の値はすべて /2026
にもかかわらず、
実際の原因はブラウザの 301 リダイレクトキャッシュという落とし穴
でした。
この記事では、
- 実装内容・方針
- バグ発生内容
- 調査内容・方針
- 解決手順・原因
- 再発防止策は何か
を整理します。
🧪 発生した現象
以下のような実装をしていました。
$year = (int) $lastSegment;
$currentYear = now()->year; // 2025
$nextYear = now()->addYear()->year; // 2026
if ($year < $currentYear) {
return redirect('/' . $nextYear, 301);
}
意図としては、
-
/2023→/2026へリダイレクト -
/2024→/2026へリダイレクト -
/2025→ リダイレクトさせない(通常表示)
ところが実際には……
/2025 にアクセスしても必ず /2026 に飛んでしまう
という状態になりました。
🔍 調査ログ(重要ポイント)
異常が起きているのを確認してから、次のように切り分けを実施しました。
✔ ① ルート定義で dd()
→ dd() の値はすでに /2026
✔ ② コントローラで dd()
→ やはり /2026 が入っている
つまり、
Laravel に届いた時点で既に
/2026になっている
という状態でした。
この時点で、
- PHPのロジックではない
- Laravelのルートでもない
- 控えめに言って挙動がおかしい
ということが確定。
🧠 問題の本質:
ブラウザの 301 永久リダイレクトキャッシュが Laravel より先に動いていた
結論としてはこれです。
調査の過程で一度だけ、
return redirect('/2026', 301);
つまり 301 Permanent Redirect(永久リダイレクト) を返したタイミングがありました。
Chrome などのブラウザは、301 を受け取るとこう判断します:
「/2025 は永久に /2026 に移動した」と記憶する
すると、
- コードを直しても
- Laravel が正しい判定をしていても
- Docker を再起動しても
- ルートキャッシュを消しても
ブラウザ自身が /2025 を /2026 に書き換えてしまい、
Laravel にリクエストが届かなくなる のです。
これが、
✔ ルートで dd() → /2026
✔ コントローラで dd() → /2026
の原因でした。
🩺 今回の現象はこう流れていた
[ブラウザ]
↓ (/2025 のリクエストを送信)
[ブラウザ内部の301キャッシュ]
「/2025 は永久に /2026!覚えてる!」
↓ (勝手に書き換え)
[サーバへ送信されるのは /2026]
↓
[Laravel(正しいロジック含む)]
dd() → 当然 /2026
つまり今回、
/2025 のリクエストは一度も Laravel に届いていなかった。
だから、どれだけロジックが正しくても、
dd() が見ていたのは「すでに書き換えられた後のURL」でした。
🛠 解決方法
最終的に次の手順で解決しました。
✔ Docker コンテナ内で Laravel キャッシュを削除
docker exec -it <コンテナID> php artisan cache:clear
docker exec -it <コンテナID> php artisan config:clear
docker exec -it <コンテナID> php artisan route:clear
docker exec -it <コンテナID> php artisan view:clear
※ Docker 環境では、ホスト側で artisan を叩いても意味がない場合が多い点に注意。
✔ ブラウザを完全終了 → 再起動
(またはシークレットモードでアクセス)
これにより、
- Laravel 側キャッシュ → 消える
- ブラウザ側の 301 キャッシュ → リセットされる
→ 本来の挙動に戻った
🔥 再発防止策(超重要)
1. デバッグ時に 301 を使わない
302(Temporary Redirect)を使うこと。
return redirect('/'.$nextYear, 302); // デバッグ中はこちら
2. 挙動がおかしい時は Network タブを見る
- 301 か?
- 302 か?
- Location は?
これを見るだけで原因が速攻でわかる。
3. Docker のキャッシュはコンテナ内で消すこと
ホスト側の artisan は無効なことも多い。
🎯 まとめ
今回のケースは、
ロジックは100%正しいのに挙動がおかしい
→ 実は Laravel の外側が原因だった
という、実務ではよくある“キャッシュの罠”でした。
ポイントは:
- 301 は強烈にブラウザにキャッシュされる
- 一度誤った 301 を返すと、修正しても Laravel に届かなくなる
- Laravel のキャッシュも Docker 内でクリアしないと意味がない
- dd() が正しく見えても、それは「ブラウザに書き換えられた後の世界」だった
この経験は、皆様の業務でも役立ちますと幸いです💪✨
Discussion