Webページや画像を一度受け取ったら、手元に保存して次の表示に使う。HTTPキャッシュは、この再利用で通信や待ち時間を減らします。ただし、保存しておいてよいことと、保存した内容をそのまま使ってよいことは別です。Cache-Controlのno-cacheとno-storeは、この違いが名前だけでは分かりにくい指示です。
ここでは、サーバーが返す応答のCache-Controlを扱います。ヘッダー名を引数に取らない通常形を対象に、保存、再利用前の確認、共有キャッシュへの保存という三つの判断を分けます。[1]
簡単にまとめると?
no-cacheは保存そのものを禁止しません。保存した応答を別の要求に使う前に、サーバーへ確認して成功する必要があります。no-storeは、キャッシュへの保存と別の要求への再利用を禁止する指示です。利用者専用・複数利用者で共有するキャッシュの両方に適用されます。must-revalidateが再検証を必須にするのは古くなった後です。まだ新鮮な応答でも確認が必要なno-cacheとは条件が違います。privateは保存先を制限します。これらの指示だけで、ログや履歴も含めた秘密保持・完全削除が保証されるわけではありません。
no-cacheは「取っておいても、使う前に確認」
たとえば、案内ページを表示するたびにサーバー側の変更を確認したいとします。一方、内容が変わっていなければ、以前受け取った本文を使っても構いません。この二つを両立できるのが、引数なしのCache-Control: no-cacheです。
キャッシュは他の保存条件を満たす応答を保存できます。しかし次の要求をその保存済み応答で満たすには、要求を検証のため転送し、成功する必要があります。単に保存時刻が新しいから、という理由で確認を省くことはできません。古い応答を出す設定があっても、この確認条件は残ります。[1、5.2.2.4節]
検証に使えるETagなどがあれば、条件付きGETで変更の有無を問い合わせられます。内容が変わっていない場合、サーバーは304を返し、キャッシュは適切な保存済み応答を更新して再利用できます。確認の通信は発生しますが、本文を毎回送り直す必要があるとは限りません。ETagは内容の版を見分ける識別子であり、保存を許可する指示そのものではありません。[1、4.3節][2、13.1.2節]
no-storeは保存済みの本文に頼らない
Cache-Control: no-storeを応答に指定すると、キャッシュはその直近の要求・応答の一部も保存せず、その応答を別の要求に使ってはいけません。ブラウザーなどの利用者専用キャッシュだけでなく、複数利用者が共有するキャッシュにも適用されます。[1、5.2.2.5節]
ここでの保存禁止は、情報を意図して不揮発性の記憶装置へ保存しないことと、転送後の揮発性メモリーからできるだけ速やかに取り除く努力をすることを含みます。通信中の一時的なバッファーまで一切存在しない、という意味ではありません。
先ほどの案内ページをこの指示で返した場合、次の表示で、その応答の保存コピーをHTTPキャッシュから取り出す流れは使えません。以前の本文を保管して検証するno-cacheとは、出発点が違います。画面が同じように再表示されても、保存しているのか、問い合わせたのか、本文を再取得したのかを分けて観測する必要があります。
10秒後と70秒後で、判断が変わる例
違いを見るため、時刻0秒に応答を受け取り、他の条件は同じとして、10秒後と70秒後に同じ表現を要求するモデルを考えます。初回の応答の年齢は0秒、ETagがあり、応答は変化していないとします。70秒後だけサーバーに接続できません。実ブラウザーの測定ではなく、指示の条件を比較するための例です。
max-age=60, must-revalidateの場合、10秒後は60秒の新鮮さの期間内なので、ほかの再利用条件も満たせば保存コピーを使えます。70秒後は古くなっており、再検証に成功するまで使えません。接続不能なら古いコピーで代用せず、エラーになります。仕様は、より適切なエラーがなければ504を推奨しています。[1、5.2.2.1〜2節]
no-cacheでは10秒後でも確認が必要です。このモデルでは検証が成功してから保存コピーを使えます。70秒後は確認できないため、保存済みの応答だけで要求を満たすことはできません。一方、no-storeでは、この応答を後で使うためのキャッシュ保存がありません。10秒後も新しく取得し、70秒後はネットワーク取得が失敗します。似たエラー表示になっても、失敗に至る条件は同じではありません。

privateは、誰のキャッシュへ置けるかを決める
利用者ごとに内容が違うページでは、鮮度だけでなく保存先の区別も必要です。引数なしのprivateは共有キャッシュによる保存を禁止し、ほかの条件を満たす利用者専用キャッシュには保存を許します。保存後にいつ確認するかは別なので、private, no-cacheなら「共有側には置かず、専用側で保存しても再利用前に確認する」という組合せになります。[1、5.2.2.7節]
判断する順番は、まず保存してよいか、次にどこへ保存してよいか、最後に確認なしで使える期間があるか、です。内容が個別かどうか、変更確認を毎回求めるか、保存コピー自体を残さない方針かを先に決めると、名前の似た指示を選び分けやすくなります。no-cacheだけを指定しても「共有キャッシュには保存されない」とは言えません。
この整理をそのまま広げられない範囲
ここまでのno-cacheとprivateは、ヘッダー名を指定する引数を付けない形です。ヘッダー名付きの形には、その項目だけを再利用や保存の対象から外す別の規則があります。RFCは、その細かな扱いが広く実装されていない点も記しています。本稿の単純な三択図に混ぜず、対象のキャッシュが実際にどう扱うかを確認する必要があります。[1、5.2.2.4、5.2.2.7節]
また、must-understandとの組合せでは、応答ステータスのキャッシュ要件を理解して実装するキャッシュがno-storeを無視すべき場合があります。この特殊な組合せは比較モデルから除いています。利用者が送る要求側のCache-Controlも、応答側と同じ役割だと決めつけず、対応する規則を読む必要があります。[1、5.2.1、5.2.2.3節]
最後に、no-storeもprivateも、それだけで秘密保持を保証する仕組みではありません。指示に従わないキャッシュや通信の盗聴を防ぐわけではなく、サーバーログ、アプリ独自の保存、画面の記録などを一括して消す命令でもありません。HTTPキャッシュの方針と、認証・暗号化・データ保持の設計は、それぞれ確認する必要があります。
出典
- RFC 9111「HTTP Caching」(2022年6月、STD 98)。3節、4節、5.2.1節、5.2.2.1〜7節。https://www.rfc-editor.org/rfc/rfc9111.html
- RFC 9110「HTTP Semantics」(2022年6月、STD 97)。13.1.2節(If-None-Match)、15.4.5節(304)。https://www.rfc-editor.org/rfc/rfc9110.html
