2026年10月8日にMDNのCache-Control本文とRFC 9110を再確認した。no-cacheは保存禁止ではなく、再利用前にoriginへ再検証する指示で、保存自体を止めるのはno-storeである。must-revalidateはfreshでなくなった応答の再検証を要求し、privateは個人化応答を共有キャッシュへ出さない判断に使う。履歴の戻る操作ではbfcacheが再検証なしにスナップショットを復元し得るため、ヘッダーの意味と画面更新・個人情報の要件を分けてテストする。
「表示速度を上げるためにキャッシュ設定を見直したいが、Cache-Controlの意味を誤解して設定を壊すのが怖くて手を付けられない」——このように感じている担当者は少なくないはずです。実際、no-cacheという名前を見て「キャッシュするな、という意味だろう」と考えるのは自然な発想です。しかし、この思い込みのまま設定すると、意図とは違う挙動を招きます。
Cache-Controlが難しく感じられるのは、ディレクティブの数が多いからではありません。本当は独立した4つの問いに答えるべきところを、一つの言葉で片付けようとしていることが原因です。この記事では、HTTPキャッシュの仕様書(RFC 9111)とMDNの定義に基づいて、その4つの問いに分解します。
30秒で要点
no-cacheは「保存するな」ではなく「保存はしてよいが、再検証なしに使うな」という意味。保存そのものを禁じるのはno-storeno-storeはプライバシーを守る確実な手段ではない、とRFC 9111自身が明記しているmust-revalidateは「検証失敗が誤動作を招く場合に限り」使うべきとRFC 9111が限定している- Cache-Controlはブラウザ(private cache)とCDN等(shared cache)の両方に効く。ディレクティブごとに効く範囲が異なる
なぜCache-Controlの設定は意図通りに効かないのか
Cache-Controlのディレクティブは一見すると「キャッシュを許可する/しない」の二択のように見えます。しかし実際には、次の4つの独立した問いに、それぞれ別々に答える必要があります。
- 保存してよいか
- 誰が保存してよいか(ブラウザだけか、CDNなどの共有キャッシュも含むか)
- どれくらいの間、新鮮とみなすか
- 再利用するとき、期限内・期限後に何を確認するか
no-cacheという1つの単語に「保存の可否」の答えを期待してしまうのは、この4つの問いを1つの言葉に圧縮しようとしているからです。実際にはno-cacheが答えているのは4つ目の問い(保存後の利用条件)であって、1つ目の問い(保存の可否)ではありません。no-cacheは期限内でも再利用前の検証を要求します。この対応関係のズレが、誤解の構造そのものです。
問い1:保存してよいか——no-cacheとno-storeの違い
RFC 9111は、no-cacheについて「検証のために転送し、成功応答を受け取らない限り、他のリクエストへの応答として使ってはならない」と定義しています。つまりno-cacheは保存自体を禁じていません。保存禁止ではありませんが、何でも保存できる許可証でもありません。メソッド・応答status・他のdirectiveなど、RFC 9111 §3の保存条件を満たした応答について、再利用前に成功した検証を求めます。ここではフィールド名を伴わない通常のno-cache/no-store/privateを扱います。
保存そのものを禁じるのはno-storeです。RFC 9111は、no-storeが指定された場合、キャッシュはリクエスト・レスポンスのいずれの一部も保存してはならず、そのレスポンスを他のリクエストに使ってもならないと定義しています。
確かなこと:no-cacheが再検証を要求するディレクティブであり保存自体を禁じていないこと、no-storeが保存自体を禁じるディレクティブであることは、RFC 9111の条文から直接確認できます。
まだ確かではないこと:個々のブラウザやCDN、プロキシがこの定義どおりに厳密に実装しているかどうかは、仕様書だけでは分かりません。挙動を保証したい場合は、実際に使用しているCDN・ミドルウェアのドキュメントで確認する必要があります。
no-storeは「安全」を保証しない
no-storeを設定すれば、機密情報を扱うページのプライバシーが守られると考えたくなりますが、RFC 9111はこの期待に釘を刺しています。同仕様は、「このディレクティブは、プライバシーを確保するための信頼できる、あるいは十分な手段ではない」と明記し、その理由として「悪意のある、あるいは不正に操作されたキャッシュはこの指示を認識・遵守しない可能性があり、通信ネットワークが盗聴に対して脆弱な場合もある」ことを挙げています。
no-storeは「キャッシュに保存させない」という指示であって、「通信経路上の盗聴」や「意図的にこの指示を無視する中間者」からデータを守る仕組みではありません。機密情報を扱うページでは、HTTPS化や認証・認可など別の対策と組み合わせます。後からno-storeを返しても、中間キャッシュが既に保存している全応答を消す命令にはなりません。機密情報の削除や露出への対応は別途必要です。
問い4:古くなった後どう振る舞うか——must-revalidateの限定的な用途
max-ageなどで新鮮さの期限が切れた(stale になった)レスポンスをどう扱うかを決めるのがmust-revalidateです。ネットワーク切断や明示された許可など、仕様が認める条件では古い応答を再利用できる場合がありますが、must-revalidateが付いているとその挙動が禁じられ、必ずサーバーへの再検証が必要になります。
ここで見落とされやすいのが、RFC 9111がこのディレクティブの使いどころを明示的に限定していることです。同仕様は「must-revalidateは、検証の失敗が誤動作——黙って実行されない金融取引など——を引き起こしうる場合に限り(if and only if)使うべきである」としています。「念のため厳しくしておく」という発想での多用は、仕様が想定する使い方ではありません。
決済確認画面のような、古い情報を見せることが実害につながるページには適していますが、一般的な記事ページや商品一覧ページにまで一律で設定すると、ネットワークが不安定な環境のユーザーが、本来表示できたはずのページを見られなくなる可能性があります。
問い2:誰が保存してよいか——private cacheとshared cache
MDNの解説によれば、Cache-Controlヘッダはリクエストとレスポンスの両方で使われ、ブラウザ等の専用キャッシュ(private cache)と、プロキシやCDN(配信を高速化するための中継ネットワーク)などの共有キャッシュ(shared cache)の両方の挙動を制御します。ディレクティブによって、リクエスト専用(max-stale・min-fresh・only-if-cachedなど)、レスポンス専用(s-maxage・must-revalidate・private・publicなど)、双方に対応(max-age・no-cache・no-store・no-transform)と役割が分かれています。
つまり「1人のユーザーのブラウザにだけ保存してよいが、CDNなど不特定多数が使う共有キャッシュには保存させたくない」といった細かい制御も可能です。privateとpublicはこの「誰が保存してよいか」という問いに答えるディレクティブであり、no-cacheやno-store(保存の可否・再検証の要否)とは別の軸にあります。通常のprivateは共有キャッシュの保存を禁止します。もし共有されていたら、ヘッダの付与位置や上書き、CDN設定などを調べます。privateはデータの暗号化ではありません。またpublicは、Authorization付き要求に対する共有キャッシュの制限を解除し得ます。個人別ページへ速度改善だけを目的に付けないでください。
判断軸:4つの問いに順番に答える
- 保存してよいか:保存を禁止するならno-store。他の場合もstatusや他のdirectiveを含む保存条件を調べます。無指定なら安全、という意味ではありません。
- 誰が保存してよいか:専用キャッシュに限定するならprivate。共有可能な場合でもpublicが必要か、認証付き応答を共有してよいかを別に確認します。
- どれくらい新鮮か:max-ageは秒数。共有キャッシュではs-maxageが優先する場合があります。取得した瞬間から丸ごと延長する値ではありません。
- 再利用時に何を確認するか:no-cacheなら期限内も成功再検証。must-revalidateならstale後の再検証を省略できません。可用性と誤動作の影響を合わせて決めます。
架空の応答で期限と検証を分ける
以下は実サービスの測定ではありません。保存条件と他の再利用条件を満たし、freshness lifetimeが120秒、遅延補正を含むcurrent ageが表の値だと仮定します。
表が収まらない場合は、横にスクロールできます
| 応答の指示 | current age | 時間の判定 | 再利用前の判断 |
|---|---|---|---|
| max-age=120 | 30秒 | 120 > 30、残り90秒 | freshだが他の再利用条件も確認 |
| max-age=120, no-cache | 30秒 | 時間だけなら残り90秒 | no-cacheにより成功再検証が必要 |
| max-age=120, must-revalidate | 120秒 | 120 > 120は偽、stale | 成功再検証なしに使わない |
| no-store | 対象外 | 保存しない指示 | TTLの長短で解決しない |
ETagなどのvalidatorで条件付き要求を行い、304 Not Modifiedなら対応する保存済み応答のmetadataを更新して再利用できます。内容が変わっていれば新しい完全な応答を使います。304は「保存しなかった」という証拠ではありません。
この表はHTTPキャッシュについてのものです。戻る操作による履歴復元やbfcacheは、通常の新しいHTTP要求と同じではありません。no-cacheだけで全ての画面復元を必ず再検証できるとは扱いません。
自分でも試せる、最小の検証
自社の主要ページを1つ選び、ブラウザの開発者ツールでそのページのレスポンスヘッダに含まれるCache-Controlの値を確認してみてください。その値が上記4つの問いのどれに答えているかを1つずつ当てはめてみると、「保存の可否」「対象範囲」「新鮮さの期限」「再利用時の条件」のうち、答えられていない項目があるかどうかが見えてきます。
判断の土台として押さえておくこと
no-cacheは保存を禁じない。禁じるのはno-storeno-storeはプライバシーの確実な保護手段ではない。通信経路の暗号化など別の対策と組み合わせるmust-revalidateは「検証失敗が誤動作を招く場合に限り」という限定的な用途向け- Cache-Controlは「保存の可否」「保存範囲」「新鮮さの期限」「再利用時の条件」という4つの独立した問いの集合体
より深く学ぶ
- TTFB(Time To First byte)完全ガイド:応答速度の測定と改善手法
- Webパフォーマンス最適化:高速サイト構築のためのベストプラクティス:キャッシュ以外の高速化施策を含む全体像
参考資料・引用元
- RFC Editor, "RFC 9111: HTTP Caching". https://www.rfc-editor.org/rfc/rfc9111.html
- MDN Web Docs, "Cache-Control header". https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cache-Control