WEB PROTOCOL

ブラウザキャッシュ(HTTP Cache)

Cache-Control、ETag、条件付きリクエストによるブラウザキャッシュの仕組みを可視化

INTERACTIVE VISUALIZATION
リクエスト
200 OK
304 Not Modified
キャッシュヒット
プロトコル
HTTP Cache
ブラウザキャッシュ
Browser
キャッシュなし
ブラウザ状態
Server
待機中
サーバー状態
進捗
1 / 7
概要
シナリオ
Cache-Controlヘッダーで指定された有効期限内のキャッシュがヒットし、サーバーにリクエストせずにレスポンスを返すフロー
ステップ1 / 7
自動再生でブラウザキャッシュの流れを順番に確認できます
ブラウザキャッシュは、以前取得したリソース(HTML、CSS、JS、画像等)をローカルに保存し、再アクセス時にサーバーへのリクエストを省略する仕組みです。
レスポンスヘッダーのCache-Controlディレクティブでキャッシュの有効期限や挙動を制御します。
キャッシュ状態
Browserキャッシュなし
まだキャッシュにリソースがない状態
Server待機中
解説

📌
ブラウザキャッシュとは

ブラウザキャッシュは、以前取得したWebリソースをローカルに保存し、再アクセス時のネットワーク通信を省略する仕組みです。HTTPレスポンスヘッダー(Cache-Control、ETag等)でキャッシュの有効期限や検証方法を制御します。冷蔵庫に例えてみましょう。毎回スーパーに買い物に行く代わりに、冷蔵庫(キャッシュ)に食材を保存しておけば、すぐに料理を始められます。ただし賞味期限(max-age)が切れたら、まだ食べられるか確認(条件付きリクエスト)してから使うか、新しいものを買い直す(200 OK)必要があります。

初回アクセス: サーバーからリソースを取得 (GET → 200 OK + Cache-Control)
キャッシュに保存 (リソース + 有効期限 + ETag)
再アクセス(期限内): キャッシュヒット (ネットワーク通信なし)
再アクセス(期限切れ): 条件付きリクエスト (If-None-Match → 304 or 200)

キャッシュはWebパフォーマンスの最も効果的な最適化手法の一つです。適切に設定すれば、ページロード時間を大幅に短縮し、サーバー負荷を劇的に削減できます。特にCSS・JS・画像などの静的アセットは、長期間キャッシュすることで初回以降のアクセスがほぼ瞬時になります。上のツールで「キャッシュヒット」シナリオを再生すると、サーバーにリクエストを送信せずにレスポンスが返る様子が確認できます。「条件付きリクエスト」シナリオでは、304 Not Modifiedによる帯域節約の仕組みが確認できます。

📌
特徴

  • 🎛️Cache-Controlレスポンスヘッダーでキャッシュの挙動を制御するディレクティブです。max-age(有効期限秒数)、no-cache(毎回サーバーに検証)、no-store(キャッシュ禁止)、public(共有キャッシュ可)、private(ブラウザキャッシュのみ)など、きめ細かな制御が可能です。複数のディレクティブを組み合わせて、リソースの種類に応じた最適なキャッシュ戦略を設定します。
  • 🔖ETagリソースの「フィンガープリント(指紋)」として機能するハッシュ値です。サーバーはリソースの内容からETagを生成し、レスポンスヘッダーに含めます。ブラウザは条件付きリクエスト(If-None-Match)でこのETagを送信し、サーバーが現在のリソースのETagと比較することで、変更の有無を判定します。リソースが1バイトでも変わればETagも変わるため、正確な変更検出が可能です。
  • 🔄条件付きリクエストIf-None-Match(ETag比較)やIf-Modified-Since(更新日時比較)ヘッダーを使って、リソースの変更有無をサーバーに問い合わせます。変更がなければ304 Not Modified(ボディなし)で応答し、帯域を節約します。数MBの画像や巨大なJSバンドルでも、変更がなければヘッダーだけの軽量な304レスポンスで済みます。
  • 📚キャッシュ階層ブラウザのキャッシュは複数の層で構成されています。memory cache(メモリ内、最速だがタブを閉じると消える)→ disk cache(ディスク上、永続的だが読み込みがやや遅い)→ network(サーバーに問い合わせ)の順で検索されます。ChromeのDevToolsのNetworkタブで「(from memory cache)」「(from disk cache)」と表示されるのがこの階層です。

📌
ユースケース

📦 静的アセット配信
React/Next.jsのビルド出力(_next/static/)にはファイル名にハッシュが含まれるため、Cache-Control: max-age=31536000, immutable を設定できます。ファイルが変更されればハッシュが変わりURLも変わるため、キャッシュの無効化が自動的に行われます。
🌐 CDNキャッシュ
Cloudflare/VercelなどのCDNは、オリジンサーバーのCache-Controlヘッダーに従ってエッジでキャッシュします。s-maxageディレクティブでCDN専用の有効期限を設定でき、ブラウザキャッシュとCDNキャッシュを独立に制御できます。
🔌 APIレスポンスキャッシュ
REST APIのレスポンスにもCache-ControlとETagを設定できます。頻繁に変わらないデータ(ユーザープロフィール等)は短いmax-ageとETagを組み合わせることで、変更がない場合は304で高速応答し、変更時は最新データを返します。
SWR / stale-while-revalidate
Next.jsのISR(Incremental Static Regeneration)やCache-Controlのstale-while-revalidateディレクティブにより、古いキャッシュを即座に返しつつ、バックグラウンドで最新データを取得・更新します。ユーザーには常に高速なレスポンスを提供しながら、データの鮮度も保てます。

📌
用語解説

Cache-Control
= キャッシュ制御ヘッダー
HTTPレスポンスヘッダーで、キャッシュの保存・有効期限・検証方法を指定するディレクティブ群です。サーバーがレスポンスに含め、ブラウザやCDNがこれに従ってキャッシュを管理します。複数のディレクティブをカンマ区切りで指定できます(例: Cache-Control: public, max-age=3600)。
Cache-Control:max-age=3600
max-age
= キャッシュ有効期限(秒)
レスポンスがキャッシュとして有効な秒数を指定します。max-age=3600なら1時間、max-age=86400なら24時間です。この期間内はサーバーに問い合わせることなくキャッシュからレスポンスを返します。期限が切れると「stale(古い)」状態となり、条件付きリクエストで検証が必要になります。
freshstalemax-age boundary
ETag
= リソースのフィンガープリント
サーバーがリソースの内容から生成するハッシュ値(例: ETag: "abc123")です。リソースが変更されるとETagも変わるため、条件付きリクエスト(If-None-Match)で変更検出に使われます。強いETag(完全一致)と弱いETag(W/"abc"、意味的に同等なら一致)の2種類があります。
ETag: "abc123"||Match = 304
Last-Modified
= 最終更新日時
リソースが最後に変更された日時を示すヘッダーです。ブラウザはIf-Modified-Sinceヘッダーでこの日時を送信し、サーバーが変更日時を比較します。ETagより精度は劣りますが(秒単位)、サーバー側の実装が簡単で広くサポートされています。ETagとLast-Modifiedの両方がある場合、ETagが優先されます。
Last-Modified:Wed, 21 Oct 2025
304 Not Modified
= 変更なしレスポンス
条件付きリクエストに対して「リソースは変更されていません」と応答するステータスコードです。レスポンスボディを含まないため、数MBの画像やJSファイルでもヘッダーだけの軽量なレスポンスで済みます。ブラウザはキャッシュ内のリソースを引き続き使用し、有効期限をリセットします。
Server304B
stale-while-revalidate
= バックグラウンド再検証
Cache-Controlディレクティブの一つで、古い(stale)キャッシュを即座に返しつつ、バックグラウンドでサーバーに最新リソースを問い合わせます。次回アクセス時には更新されたキャッシュが使われます。Next.jsのISRやVercelのEdge Cachingで活用されており、ユーザーには常に高速なレスポンスを提供しながらデータの鮮度も保てます。
freshswrstalerevalidate in background

📌
キャッシュ判定フローチャート

ブラウザがリソースをリクエストしたとき、キャッシュをどう扱うかの判定フローです。

1
キャッシュにある?
ブラウザのキャッシュストレージにリソースが存在するか確認します。なければサーバーにGETリクエストを送信し、レスポンスをキャッシュに保存します。
2
有効期限内?(max-age)
Cache-Control: max-ageの有効期限内であれば「fresh(新鮮)」状態です。サーバーへのリクエストなしでキャッシュからレスポンスを返します(キャッシュヒット)。
3
条件付きリクエスト送信
期限切れの場合、If-None-Match(ETag)またはIf-Modified-Since(Last-Modified)ヘッダーを付けてサーバーに問い合わせます。
4
304 or 200?
リソースが変更されていなければ304 Not Modified(キャッシュを継続使用)。変更されていれば200 OKで新しいリソースを返し、キャッシュを更新します。
RequestCache?Fresh?Yes → Cache Hit!NoIf-None-Match304200キャッシュ判定フロー

📌
Cache-Controlディレクティブ一覧

ディレクティブ説明
max-age=NレスポンスがN秒間有効。この間はサーバーに問い合わせずキャッシュを使用。例: max-age=3600(1時間)
no-cacheキャッシュに保存するが、使用前に毎回サーバーに検証(条件付きリクエスト)が必要。「キャッシュするな」ではなく「検証しろ」の意味
no-storeキャッシュに一切保存しない。機密データ(口座残高、個人情報等)に使用。最も厳格なディレクティブ
publicCDN等の共有キャッシュに保存可。認証が必要なレスポンスでも共有キャッシュに保存したい場合に明示的に指定
privateブラウザのキャッシュにのみ保存可。CDN等の共有キャッシュには保存されない。ユーザー固有のデータに使用
must-revalidateキャッシュが古くなったら必ずサーバーに検証する。オフライン時に古いキャッシュを使うことを禁止
s-maxage=N共有キャッシュ(CDN等)専用のmax-age。ブラウザのmax-ageとは独立に設定でき、CDNのキャッシュ期限を別途制御
immutableリソースが変更されないことを宣言。条件付きリクエストも送信しない。ハッシュ付きファイル名のアセットに最適
実際のプロジェクトでは、リソースの種類に応じてこれらのディレクティブを組み合わせて使用します。例: 静的アセットには「public, max-age=31536000, immutable」、APIレスポンスには「private, no-cache」。

関連コンテンツ

HTTP通信

HTTP通信

ブラウザとサーバー間のHTTPリクエスト/レスポンスの仕組みを可視化

HTTP/1.1 vs HTTP/2

HTTP/1.1 vs HTTP/2

直列リクエストと多重化の違いをウォーターフォールチャートで比較

セッション vs Cookie vs JWT

セッション vs Cookie vs JWT

認証方式の違いと使い分けを可視化

CDNエッジキャッシュ

CDNエッジキャッシュ

CDNのエッジキャッシュとオリジンサーバーの関係と仕組みを可視化

CORS

CORS

ブラウザのクロスオリジン制約とCORSヘッダーによるアクセス制御の仕組みを可視化

HTTPステータスコード

HTTPステータスコード

1xx〜5xxの各グループと代表的なステータスコードの意味を可視化