Vercel以外でNext.jsのgetStaticPropsを使うとCDNに長期間キャッシュされるかも
環境
- Next.js on GAE(Google App Engine)の構成でこの問題を確認しています。
- Next.js on Cloud Runでも同じ問題が発生すると思います。
- Vercelにデプロイしている場合にはこの問題は発生しないと思います。
-
revalidate
は指定していません(= ISRは使用していません)。GAEではISRがうまく動かないためです。
直面した問題
ふとgetStaticProps
を使っているページが本番環境で[1]CDNに長期間キャッシュされることが分かりました。レスポンスヘッダを見るとCache-Control: s-maxage=31536000, stale-while-revalidate
という値が設定されています。CDNのキャッシュが削除されなかった場合、最大で31536000秒キャッシュされうるということです。
getStaticProps
を使っているページはビルド時点で静的ファイルとして出力されるため、SSR(getServerSideProps
)よりもリクエスト時のサーバーの負荷を抑えることができます。
しかし、ヘッダにCache-Control: s-maxage=31536000
が指定されてしまった場合、リリースのタイミングでCDNのキャッシュをクリアしないと古いバージョンのファイルが配信され続けてしまう可能性が出てきます。
この挙動の原因
この挙動の原因となっているのは、Next.jsの以下の部分です。
...
} else if (typeof options.revalidate === 'number') {
if (options.revalidate < 1) {
throw new Error(
`invariant: invalid Cache-Control duration provided: ${options.revalidate} < 1`
)
}
res.setHeader(
'Cache-Control',
`s-maxage=${options.revalidate}, stale-while-revalidate`
)
} else if (options.revalidate === false) {
res.setHeader('Cache-Control', `s-maxage=31536000, stale-while-revalidate`)
}
...
getStaticProps
が使われている、かつ revalidate
が指定されていない場合にはres.setHeader('Cache-Control',
s-maxage=31536000, stale-while-revalidate)
が呼び出されるようです。revalidate: 秒数
を指定した場合、その秒数がs-maxage
の値として設定されるようです。
関連するページ
以下のDiscussionでこの件について指摘されています。
2022/01/26時点ではNext.jsのメンテナによる返信はありません。
個人的な感想
👆 のソースコードの部分だけでも条件分岐が数多くあり、「Vercelにデプロイすればzero configでいろいろいい感じになる」と「それ以外のNode.jsランタイムでも問題なく動かす」の両方を満たすようにフレームワークを設計するのはすごく大変なんだろうな…と改めて思いました
-
ローカル開発環境では
Cache-Control
の値が書き換えられるため問題なし ↩︎