HTTPキャッシュの深淵:Cache-ControlでWebのパフォーマンスを制御する「現場の流儀」
ネットワークエンジニアとして現場に立っていると、必ずと言っていいほどぶつかる壁が「キャッシュ」だ。「更新したはずのJSが反映されない」「意図せず個人情報がプロキシに保存されてしまった」。これらはすべて、RFC 7234で定義された`Cache-Control`ヘッダーの解釈を誤った結果に過ぎない。
今日は、教科書的な定義を超えて、我々が実務でどうこのヘッダーと向き合い、Web APIやインフラを堅牢に設計すべきかを語ろう。
—
1. キャッシュの意思決定:主要ディレクティブの挙動
`Cache-Control`は、ブラウザやCDN、そして中間のプロキシサーバに対する「キャッシュの取扱説明書」だ。まずは、現場で頻出する主要なディレクティブを整理しよう。
`max-age=`:生存期間の定義
もっとも基本的なディレクティブだ。ここには「このコンテンツを何秒間、鮮度が高いと見なすか」を指定する。例えば `max-age=3600` なら、1時間はキャッシュが利用される。
`no-cache`:思考停止を許さない「検証」
初心者が最も誤解するのがこれだ。「キャッシュしない」という意味ではない。「キャッシュはしてもいいが、使う前に必ずオリジンサーバに検証(再検証)に行け」という意味だ。ETagやLast-Modifiedを使って、中身が更新されていないか確認するプロセスが必須となる。
`no-store`:情報の機密を守る鉄壁
「一切保存するな」。個人情報やセッション情報を含むAPIレスポンスには、必ずこれを付与しなければならない。ブラウザのローカルディスクにも、CDNのメモリにも、一切の痕跡を残してはならないシーンで使う。
`must-revalidate`:期限切れ=即無効
`max-age`が過ぎた後、サーバとの通信が失敗したとしても、期限切れのキャッシュを返してはならないことを強制する。銀行の残高表示など、情報の鮮度が信頼性に直結する箇所では必須のオプションだ。
—
2. 通信フロー:ブラウザとサーバの駆け引き
簡単なシーケンスで考えると、キャッシュの挙動は以下のようになる。
1. 初回アクセス: `max-age=60` が返る。ブラウザはこれを60秒間ローカルに保存。
2. 2回目(60秒以内): ブラウザはネットワークを見に行かず、ディスクから即座にレスポンスを返す(`200 OK (from disk cache)`)。
3. 3回目(60秒経過後): ブラウザは `If-None-Match: “tag-123″` というヘッダーを付けてサーバに問い合わせる。
4. 検証結果: コンテンツが変わっていなければサーバは `304 Not Modified` を返す。これで通信量を最小化する。
—
3. 実践:インフラとコードでの設定例
Nginxでの設定例(静的ファイル)
`nginx.conf`でキャッシュ戦略を定義するのは、インフラエンジニアの基本スキルだ。
/static配下のファイルには1日のキャッシュを許可
location /static/ {
expires 1d;
add_header Cache-Control “public, max-age=86400”;
}
APIエンドポイントはキャッシュを禁止
location /api/ {
add_header Cache-Control “no-store, no-cache, must-revalidate, proxy-revalidate”;
add_header Pragma “no-cache”; # 古いクライアントへの保険
}
Fetch APIでの制御
ブラウザ側でリクエスト時に挙動を制御したい場合もある。
// APIから常に最新を取得したい場合(キャッシュを無視)
fetch(‘/api/user-profile’, {
method: ‘GET’,
headers: {
// キャッシュを強制的にスキップさせる
‘Cache-Control’: ‘no-cache’
}
})
.then(response => response.json())
.then(data => console.log(data));
—
4. 現場のシニアからのアドバイス:デバッグのコツ
最後に、トラブルシューティング時の心構えを伝えておく。
- curlを活用せよ:
`curl -I -v https://example.com/api` を叩いて、レスポンスヘッダーに意図した `Cache-Control` が含まれているかを確認する。これがすべての出発点だ。
- CDNの挙動を疑え:
ブラウザのキャッシュをクリアしても直らない場合、CDN(CloudFrontやCloudflare)のキャッシュが残っているケースが多い。パージ(削除)コマンドを叩くか、キャッシュキーの設計を見直す必要がある。
- ブラウザのDevTools:
Chromeの「Network」タブで、`Size`列に注目しよう。`memory cache` や `disk cache` と表示されていれば、それはブラウザが気を利かせた(あるいは君が指示した)結果だ。
キャッシュはWebパフォーマンスの要だが、同時に「更新されない」という最大の罠でもある。`no-store`と`no-cache`の違いを脊髄反射で語れるようになるまで、何度もヘッダーを眺めてみてほしい。
ネットワークは生き物だ。パケットの行方を想像し、ブラウザのメモリ領域を意識する。その視点を持つだけで、君が書くコードは一段階上の信頼性を獲得するはずだ。
コメント