Next.js の App Router で、layout の中で条件付きの redirect() を書きました。本番で有効にした直後、飛び先のページで GET /…?_rsc=… が 1秒に約8回飛び続け、画面が操作できなくなりました。ユニットテストも、そのページ単体の e2e も通っていました。
構成(ループした形)
app/
app/
layout.tsx ← 二段階認証が未設定なら /app/account/mfa へ redirect
account/
mfa/
page.tsx ← 登録ページ。これも /app の layout の配下
原因
App Router は、共通の layout をクライアント遷移のたびに作り直しません。ブラウザに残った「redirect を出す layout」が、登録ページの上でも redirect を出し続けます。
middleware でパスをヘッダに入れて「登録ページなら redirect しない」と例外にする方法も試しましたが、layout が再実行されないので、原理的に効きませんでした。
直し方
登録ページを route group に出して、ゲートのある layout の外に置きました。
app/
(mfa-enrollment)/
app/account/mfa/page.tsx ← URL は同じ。layout は別
app/
layout.tsx ← ゲートはこちらだけ
route group のフォルダ名(かっこ付き)は URL に出ないので、URL を変えずに layout だけを分けられます。
次から気をつけること
- layout で redirect するときは、飛び先がその layout の外にあるかを必ず確かめる
- 単体ページの e2e では捕まらない。着地してから5秒間の
_rscリクエスト数を数えるテストにすると捕まえられる - 強制の切り替え(全員に必須にする等)は、①すぐ戻すコマンドを手元に用意 ②ログでリクエスト数を見ながら ③自分が操作する直前に入れる
生成AI(Claude Code)に書かせて一人で会社を回している記録を note に書いています。
https://note.com/kaito_cometa