Cookies can only be modified の直し方
実際に出るエラー
ページや部品を描く途中で Cookie を書いたり消したりしたときに出るエラーです。
いつ出るのか
ページや部品を描いている途中で Cookie を変えようとすると出ます。実機で確かめました。
import { cookies } from 'next/headers'
export default async function Page() {
const c = await cookies()
c.set('session', 'abc') // ここで止まる
return <p>ログインしました</p>
}
消すときも同じです。ログアウトのつもりで c.delete('session') をページに書いても、同じ文言になりました。
なぜ書けないのか
ページを描くのは表示のための処理です。開いただけで状態が変わってはいけません。同じページを2回開いたら2回ログインした、では困ります。
だから書き込みは、送信を受け取る側に限られています。
| 場所 | 読む | 書く・消す |
|---|---|---|
| ページ・レイアウト(Server Component) | できる | できない |
| Server Function(フォームの送信先) | できる | できる |
| Route Handler(route.ts) | できる | できる |
直し方
書き込みを、フォームの送信先へ移します。
ページで書く
export default async function Page() { const c = await cookies() c.set('session', key) return <p>ログインしました</p> }
開いた瞬間に 500。
送信先で書く
'use server' export async function signIn(formData: FormData) { const c = await cookies() c.set('session', key, { httpOnly: true }) redirect('/mypage') }
書いてから、別のページへ移す。
実際にこの形で動いているものが最小構成のログインにあります。説明用に書き直したものではなく、そのページを動かしている本物のファイルです。ログアウトも同じく送信先で delete しています。
直したあとに確かめること
- 本番ビルドで一度開く。このエラーは開くまで出ません
- 送信先で、呼んだのが誰かを確かめているか。Server Function は画面を通らずに直接呼ばれ得ます(認証をどこで確かめるか)
- そのページに
force-staticを付けていないか。付いていると、ログインしていない状態の画面が全員に配られます(キャッシュの考え方)
出典
このページの内容は上記の一次情報を基準に書いています。個人ブログや二次情報を根拠にしていません。