HTTP Cache-Control: immutable と stale-while-revalidate の違い

HTTP Performance Frontend Backend
結論

完全不変なアセットには immutable、裏で最新化したいデータには stale-while-revalidate を使います。

# MDN / RFC 8246 仕様:ハッシュ付きJS/CSS用キャッシュヘッダー
Cache-Control: public, max-age=31536000, immutable

# MDN / RFC 5861 仕様:SWR型キャッシュヘッダー
Cache-Control: public, max-age=60, stale-while-revalidate=3600

MDN公式仕様:2つの拡張ディレクティブの挙動比較

評価軸immutable (RFC 8246)stale-while-revalidate (RFC 5861)
主な用途ハッシュ付きJS/CSS(例: main.a8f9b.jsTopページ、動的コンテンツ、SWR通信
リロード(F5)時の挙動サーバーへの304確認リクエストを完全切断古いキャッシュを即時返しつつバックグラウンド取得
ユーザーへのデータ反映キャッシュ期限内は常に同一ファイルを返却1回目は古いデータ、2回目描画時に最新が反映

実際に起こる事故:index.htmlimmutable を付与して詰むトラブル

Web開発現場で発生する最も深刻なトラブルは、ファイル名が変わらない HTML ファイル(index.html)に immutable を指定してしまう事故です。

immutable が付与されると、ブラウザはユーザーがF5更新ボタンを押そうと、max-age 期間中はサーバーにリクエスト(If-None-Match)を一切送信しなくなります。その結果、新バージョンをデプロイしても index.html 内の参照ファイルパスが書き換わらず、ユーザーはブラウザのキャッシュを完全手動削除しない限り永遠に新画面が表示されない障害が発生します。


適切なヘッダー割り当てルール

  1. index.html などエントリーポイント
    Cache-Control: no-cache(毎回サーバーに304確認)または max-age=0, must-revalidate
  2. bundle-[hash].js, style-[hash].css, 画像アセット
    Cache-Control: public, max-age=31536000, immutable
  3. API レスポンス・更新頻度の高いコンテンツ
    Cache-Control: public, max-age=10, stale-while-revalidate=60