本記事ではProduction環境で不具合を出したお焚き上げ記事です。
みなさんは私の屍を超えてStgまでで対応する / Productionに出してしまったら速攻で対応しましょう。
redirect function in Next.js
Webの世界では当たり前に使われるリダイレクトですがもちろんNext.jsでも利用可能です。
Next.jsでリダイレクトを実装したい時にはredirectを使うことで実現できます。
import { redirect } from 'next/navigation'
export function Redirect() {
redirect('/somewhere')
}
redirectの第一引数にpathをパスしてあげる。とても簡単ですね。
このとき 'use client'
を明示していない場合はServer Sideで実行されます。
RSC
Next.jsのページはコンポーネントから生成されます。ref: Server and Client Component
詳細は省略しますがざっくり効率的にWebページをレンダリングするためにデータをチャンク化してclientに渡す仕組みと考えていただいて差し支えありません。
CDN
Next.jsから少し離れますが、静的なWebページやJS, CSS, 画像ファイルは毎回オリジンサーバーに取得するとネットワークのデータ転送の遅延やオリジンサーバーの負荷が上がります。
このときにはCDNを使ってエッジサーバーでデータを返すようにすると改善されます。
AWSで言うところのCloudFrontですね。
特定のpathに対してキャッシュをもたせることで都度オリジンサーバーへのアクセスをしなくて済むようになります。
不具合
この状況でredirectをするページをデプロイしたところHTMLが返ってくるはずのURLから何やら見慣れない文字列が返ってくるときがありました。
(毎回じゃなかったのが辛かったところ)
1:$Sreact.fragment
2:....
...
調査中に知りましたがこれはRSC Payloadが表示されている状態です。
原因
RSC payloadは効率的にWebサイトをレンダリングする仕組みですが、そのためにリクエストのクエリに ?_rsc=xxx
のような文字列が含まれるときがあります。
参考にしたのは以下のissueです。
CDNのキャッシュ時にこの_rsc
を含むようにしてしまうとRSC PayloadがキャッシュされてHTMLがブラウザで表示できなくなる可能性があります。
まとめると:
- Server ComponentでRedirectを実行
- クライアントが
?_rsc=xxx
パラメータ付きでリクエスト - CDNがこのパラメータを含めてキャッシュ
- 次回以降、通常のHTMLリクエストに対してRSC Payloadが返される
という流れになります。
対処
我々の場合は、本来不要なタイミングでredirectを実行していたことが原因でした
そのため本来であればredirectを含めずに実装を進めるべきでした。
またredirectが必要ある場合はCDN側で_rsc
を含めないようにする設定が必要です。
Terraformを使っている場合は以下のように設定すると解決できます。
resource "aws_cloudfront_cache_policy" "nextjs_policy" {
name = "sample name"
comment = "Cache policy for Next.js that excludes RSC parameters"
default_ttl = 3600
max_ttl = 86400
min_ttl = 0
parameters_in_cache_key_and_forwarded_to_origin {
enable_accept_encoding_brotli = true
enable_accept_encoding_gzip = true
query_strings_config {
query_string_behavior = "allExcept"
query_strings {
items = ["_rsc"]
}
}
}
headers_config {
header_behavior = "none"
}
cookies_config {
cookie_behavior = "none"
}
}