HTTP キャッシュ:Cache-Control と ETag は半分ずつ担う

Cache-Control は「リクエストを送るか」を、ETag は「送った後で本文を省けるか」を決めます。混同すると片方を直しても直りません。

キャッシュの問題はほぼ二つの独立した問いに分解できます。このリクエストを送るべきか、そして送った後で本文を省けるか。前者は Cache-Control、後者は ETag と Last-Modified が担います。

前半:リクエストを送るか

Cache-Control: public, max-age=31536000, immutable

ハッシュ付きファイル名のビルド成果物はこうあるべきです。一年、immutable、リクエスト自体を送りません。

Cache-Control: no-cache

no-cache は最も誤読される指令です。キャッシュしないという意味ではありません。「キャッシュしてよいが、使うたびに検証が必要」です。保存自体を禁じるのは no-store です。

指令 保存するか リクエストを送るか
max-age=0 する 送る(検証あり)
no-cache する 送る(検証あり)
no-store しない 送る(書き込みなし)
immutable する 有効期間内は送らない

後半:本文を省けるか

サーバが ETag: "abc123" を返し、次回ブラウザが付けます。

If-None-Match: "abc123"

変化が無ければ 304 Not Modified で本文はありません。節約できるのは転送量で、往復は変わりません。リクエストは依然として発生します。

etag on;

組み合わせ

目的 Cache-Control 検証子
ハッシュ付き静的資産 max-age=31536000, immutable 不要
HTML ページ no-cache ETag
キャッシュ可能な API max-age=60, must-revalidate ETag
機微なデータ no-store 無意味

HTML は通常 no-cache と ETag の組み合わせです。変更は即座に反映され、変化が無ければ 304 一つで文書全体を省けます。

つまずきやすい点

ETag の生成方法を変えると全キャッシュが一度無効になります。 mtime 由来なら、内容が同じでも再デプロイで全クライアントが再取得します。内容ハッシュの方が安定します。

CDN はヘッダを書き換えたり飲み込んだりします。 オリジンが max-age=60 でも、CDN が独自規則でより長く保持することがあります。「更新されない」を調べるときは、オリジンより先に CDN の状態ヘッダ(eo-cache-status、cf-cache-status)を見てください。

Cache-Control は問い合わせるかを、ETag は答えるかを決めます。一緒に語ると永遠に直りません。

← 記事一覧に戻る

コメント

…