redirect が効かない(NEXT_REDIRECT)の直し方
実際に出るエラー
redirect を try で囲むと、移動せずに catch へ落ちて Error: NEXT_REDIRECT を受け取ります。
何が起きているか
redirect は、呼んだその場で例外を投げて処理を止めます。Next.js はその例外を受け取って、移動先を返します。
try で囲むと、Next.js より先に自分の catch がその例外を受け取ります。
import { redirect } from 'next/navigation'
export default async function Page() {
try {
const user = await getUser()
if (!user) redirect('/login') // ← ここで例外が投げられる
return <p>ようこそ</p>
} catch (e) {
// ← 移動の合図がここに届いてしまう
return <p>読み込みに失敗しました: {String(e)}</p>
}
}
実機で確かめました。ページは 200 で表示され、移動しません。画面には「読み込みに失敗しました: Error: NEXT_REDIRECT」と出ます。
- Serverredirect('/login') を呼ぶ
移動先を載せた例外を投げる。
- Server自分の catch が受け取る
try で囲んでいると、Next.js より先にここへ来る。
- Servercatch が画面を返す
Next.js は移動の合図を受け取れない。200 で失敗の画面が出る。
受け取った例外の digest には、移動先がそのまま入っていました(実機で NEXT_REDIRECT;replace;/b;307;)。Next.js はこれを見て移動させています。
直し方
| 書き方 | 結果 |
|---|---|
| try の中で呼び、catch で画面を返す | 200。移動しない。catch の画面が出る |
| redirect を try の外で呼ぶ | 307 で /login へ移動する |
| catch の先頭で unstable_rethrow(e) | 307 で /login へ移動する |
1. redirect を try の外に出す(まずこれ)
失敗しうる処理だけを try で囲み、判定と移動は外でします。
export default async function Page() {
let user
try {
user = await getUser()
} catch {
return <p>読み込みに失敗しました</p>
}
if (!user) redirect('/login') // ← try の外
return <p>ようこそ</p>
}
公式ドキュメントも、try を使うときは redirect をその外で呼ぶよう書いています。
2. catch の先頭で unstable_rethrow を呼ぶ
構造上、try の中で呼ぶしかないときの方法です。
import { redirect, unstable_rethrow } from 'next/navigation'
// ...
} catch (e) {
unstable_rethrow(e) // ← Next.js の合図なら投げ直す
return <p>読み込みに失敗しました</p>
}
unstable_rethrow は、受け取った例外が Next.js の合図なら投げ直し、そうでなければ何もしません。本当の失敗だけが catch の残りに進みます。
同じ作りのもの
公式ドキュメントによると、notFound と permanentRedirect も同じく例外を投げてNext.js に伝える作りです。try で囲むと同じように catch に拾われます。unstable_rethrow はこれらもまとめて投げ直します。
直したあとに確かめること
- ログインしていない状態で開き、アドレスが /login に変わるかを見る
- 開発ツールのネットワークで、最初の応答が 307 になっているかを見る
- 取得を本当に失敗させたときに、失敗の画面が出るかを見る(catch を消していないか)
出典
- nextjs.org/docs/app/api-reference/functions/redirect
- nextjs.org/docs/app/api-reference/functions/unstable_rethrow
このページの内容は上記の一次情報を基準に書いています。個人ブログや二次情報を根拠にしていません。