#はじめに

「同じ画像を何度もダウンロードするのは無駄では?」——その通りです。HTTPキャッシュは、この無駄を省くための仕組みです。

適切にキャッシュを設定すれば、ページの読み込みが高速化し、サーバーの負荷も軽減できます。しかし、設定を誤ると「更新したのに古い内容が表示される」という問題に悩まされます。

この記事を読むと、以下のことができるようになります:

  • HTTPキャッシュの基本的な仕組みを理解できる
  • ブラウザがキャッシュを使うかどうかの判断基準がわかる
  • DevToolsでキャッシュの状態を確認できる

#なぜキャッシュが必要か

Webページを開くたびに、多くのリソースをダウンロードします。

index.html → 10KB
style.css → 50KB
app.js → 200KB
logo.png → 30KB
hero.jpg → 500KB
合計: 約800KB

毎回すべてをダウンロードすると:

  • ユーザー: ページ表示が遅い
  • サーバー: 負荷が高い
  • 通信: 帯域を無駄に消費

キャッシュがあれば、変更のないリソースはローカルから読み込めます。

#キャッシュの種類

#ブラウザキャッシュ(プライベートキャッシュ)

各ユーザーのブラウザに保存されるキャッシュです。

[ブラウザ] ←→ [ブラウザキャッシュ] ←→ [サーバー]

特徴:

  • ユーザーごとに独立
  • ユーザー固有のデータもキャッシュ可能
  • ブラウザのディスクに保存

#共有キャッシュ

複数のユーザー間で共有されるキャッシュです(CDN、プロキシなど)。

[ブラウザA] ←┐
             ├→ [CDNキャッシュ] ←→ [サーバー]
[ブラウザB] ←┘

特徴:

  • 複数ユーザーで共有
  • ユーザー固有のデータはキャッシュ不可
  • サーバーへのリクエストを大幅に削減

#キャッシュの基本フロー

#1. 初回リクエスト

[ブラウザ]                           [サーバー]
    |                                    |
    |------ GET /style.css ------------->|
    |                                    |
    |<----- 200 OK ----------------------|
    |       Cache-Control: max-age=3600  |
    |       [CSSの内容]                   |
    |                                    |
    ↓ ブラウザがキャッシュに保存

#2. 2回目のリクエスト(キャッシュ有効期間内)

[ブラウザ]              [キャッシュ]
    |                       |
    |------ GET /style.css →|
    |                       |
    |  キャッシュから返す     |
    |  (サーバーへのリクエストなし)
    |                       |
    |<----- 200 OK ---------|

サーバーへのリクエストは発生せず、キャッシュから即座に返されます。

#3. キャッシュ有効期限切れ後

有効期限が切れると、サーバーに再度リクエストします。このとき「条件付きリクエスト」を使って、リソースが変更されているかを確認できます(後の記事で詳しく学びます)。

#Cache-Controlヘッダー

キャッシュの動作を制御する最も重要なヘッダーです。

#レスポンスでの使用

サーバーがクライアントにキャッシュ方法を指示します。

Cache-Control: max-age=3600

#リクエストでの使用

クライアントがキャッシュの使用方法を指定します。

Cache-Control: no-cache

#基本的なディレクティブ

ディレクティブ意味
max-age=NN秒間キャッシュを有効とする
no-cacheキャッシュ前にサーバーで検証必須
no-storeキャッシュを一切禁止
public共有キャッシュでもキャッシュ可能
privateブラウザキャッシュのみ可能

#freshとstale

キャッシュされたリソースは、2つの状態を持ちます。

#fresh(新鮮)

有効期限内のキャッシュ。サーバーへの確認なしに使用できます。

max-age=3600 で取得
現在: 取得から30分後
→ fresh(残り30分有効)

#stale(古い)

有効期限が切れたキャッシュ。使用前にサーバーへの確認が必要です。

max-age=3600 で取得
現在: 取得から2時間後
→ stale(期限切れ)

staleなキャッシュは即座に破棄されるわけではなく、条件付きリクエストで再検証できます。

#DevToolsでキャッシュを確認

#Networkタブでの確認

  1. DevToolsを開く
  2. Networkタブを選択
  3. リクエストを確認

確認ポイント:

意味
Status200 (from disk cache) = ディスクキャッシュから
200 (from memory cache) = メモリキャッシュから
304 Not Modified = 条件付きリクエストでキャッシュ使用
Size(disk cache) または (memory cache) と表示

#キャッシュの無効化

開発中はキャッシュを無効化したいことがあります。

  1. Networkタブを開く
  2. 「Disable cache」にチェック
  3. DevToolsを開いている間、キャッシュが無効に

または、ハードリロード:

  • Mac: Cmd + Shift + R
  • Windows: Ctrl + Shift + R

#レスポンスヘッダーの確認

  1. リクエストをクリック
  2. Headersタブを選択
  3. Response HeadersセクションでCache-Controlを確認

#キャッシュの判断フロー

ブラウザがリソースを取得する際の判断フローです。

リクエスト発生

    ├── キャッシュにある?
    │   │
    │   ├── No → サーバーにリクエスト
    │   │
    │   └── Yes → キャッシュはfresh?
    │            │
    │            ├── Yes → キャッシュを使用
    │            │
    │            └── No → 条件付きリクエスト
    │                     │
    │                     ├── 304 → キャッシュを使用
    │                     │
    │                     └── 200 → 新しいレスポンスを使用

#ヒューリスティックキャッシュ

Cache-ControlExpiresが指定されていない場合、ブラウザは「ヒューリスティック(経験則)」でキャッシュ期間を推測します。

# 一般的な計算式
キャッシュ期間 = (現在時刻 - Last-Modified) × 10%

# 例: Last-Modifiedが100日前
キャッシュ期間 = 100日 × 10% = 10日

予測できない動作を避けるため、常に明示的にCache-Controlを指定することが推奨されます。

#まとめ

  • HTTPキャッシュはパフォーマンス向上とサーバー負荷軽減に重要
  • ブラウザキャッシュ(プライベート)と共有キャッシュ(CDN等)がある
  • Cache-Controlヘッダーでキャッシュの動作を制御
  • fresh(有効期限内)とstale(期限切れ)の状態がある
  • DevToolsのNetworkタブでキャッシュ状態を確認できる

#次のステップ

HTTPキャッシュの基本がわかったところで、次はCache-Controlディレクティブを詳しく学びましょう。no-cacheno-storeの違い、publicprivateの使い分けなど、実務で必要な知識を身につけます。

#参考リンク