1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【図解でわかるWeb技術⑧】キャッシュ戦略 ― ブラウザ・サーバー・CDNキャッシュを完全理解する

1
Posted at

はじめに

「ページをリロードしたら一瞬で表示されるけど、初回は遅かった。なぜ?」

その答えは キャッシュ です。Webの世界では、同じデータを何度もダウンロードしなくて済むように、さまざまなレイヤーでキャッシュが活用されています。

しかし、キャッシュを正しく設定しないと 「更新したのに古い表示のまま」 という厄介な問題が起こります。この記事では、Cache-ControlやETagの仕組みから実践的な設定パターンまでを図解で解説します。

この記事は 「図解でわかるWeb技術の仕組み」シリーズ の第8回です。
第7回:WebSocket ― 双方向リアルタイム通信を先に読むと、よりスムーズに理解できます。


1. キャッシュとは ― なぜ必要なのか

一言でいうと

キャッシュ とは、一度取得したデータのコピーを近い場所に保存しておき、次回以降のアクセスを高速化する仕組みです。

キャッシュがないとどうなるか

ブラウザでページを開くたびに、すべてのリソース(HTML、CSS、JS、画像)をサーバーから再ダウンロードします。

問題 影響
表示速度の低下 ユーザー体験が悪化
サーバー負荷の増大 同じデータを何度も生成・転送
帯域の浪費 モバイル回線ではデータ量がコストに直結

2. Webキャッシュの3つのレイヤー

Webのキャッシュは 3つの層 で構成されています。リクエストがオリジンサーバーに届く前に、各レイヤーでキャッシュが確認されます。
08_cache_overview.png

各レイヤーの特徴

レイヤー 保存場所 対象ユーザー 主な用途
ブラウザキャッシュ ユーザーの端末 そのユーザーのみ 再訪時の高速表示
CDNキャッシュ エッジサーバー 全ユーザー 静的ファイルの高速配信
サーバーキャッシュ アプリサーバー/Redis 全リクエスト DB負荷の軽減

リクエストの流れ:ブラウザキャッシュ → CDNキャッシュ → サーバーキャッシュ → DB

キャッシュがヒットすれば、その時点でレスポンスを返せるため、後段への問い合わせが不要になります。


3. Cache-Control ― キャッシュの司令塔

Cache-Control は、HTTPレスポンスヘッダーでキャッシュの動作を制御する 最も重要なディレクティブ です。

08_cache_control.png

主要ディレクティブの詳細

publicprivate

Cache-Control: public, max-age=3600
Cache-Control: private, max-age=3600
  • public: CDN・プロキシを含め、どこでもキャッシュしてよい
  • private: ブラウザだけがキャッシュしてよい(CDNには保存されない)

ユーザー固有のデータ(マイページ、カート情報など)には必ず private を指定してください。 public にすると、CDN上に他ユーザーのデータがキャッシュされ、情報漏洩につながるリスクがあります。

max-age

Cache-Control: max-age=86400

キャッシュの 有効期間(秒数) を指定します。この期間中はサーバーへの問い合わせなしでキャッシュを使用します。

設定例 期間 用途
max-age=0 0秒(毎回検証) 動的コンテンツ
max-age=3600 1時間 頻繁に更新されるAPI
max-age=86400 1日 画像ファイル
max-age=31536000 1年 ハッシュ付きJS/CSS

no-cacheno-store の違い

この2つは 名前が紛らわしい ですが、動作は全く異なります。

ディレクティブ キャッシュ保存 サーバー検証 用途
no-cache する 毎回必要 HTMLページ、APIレスポンス
no-store しない - 機密データ(パスワード、口座情報)

no-cache は「キャッシュするな」ではありません。 正しくは「キャッシュしてよいが、使う前に必ずサーバーに確認しろ」という意味です。「キャッシュするな」は no-store です。


4. ETag / Last-Modified ― 条件付きリクエスト

no-cache でサーバーに確認するとき、毎回フルでデータを返していたら効率が悪いです。そこで登場するのが 条件付きリクエスト です。

08_cache_etag_flow.png

仕組み

  1. 初回アクセス: サーバーがレスポンスに ETagLast-Modified を付与
  2. 2回目以降: ブラウザが If-None-Match(ETag用)や If-Modified-Since(Last-Modified用)を送信
  3. 変更なし: サーバーは 304 Not Modified(ボディなし)を返す → ブラウザはキャッシュを使う
  4. 変更あり: サーバーは 200 OK + 新しいデータを返す

ETag vs Last-Modified

# ETag(コンテンツのハッシュ値)
ETag: "abc123def456"

# Last-Modified(最終更新日時)
Last-Modified: Mon, 01 Jan 2026 00:00:00 GMT
比較項目 ETag Last-Modified
精度 バイト単位で変更を検出 秒単位
計算コスト ハッシュ計算が必要 ファイルシステムから取得(軽量)
推奨度 高(より正確) 中(フォールバック用)

ETagとLast-Modifiedは併用できます。 両方あればETagが優先されます。Last-ModifiedはETag非対応のクライアントへのフォールバックとして有用です。


5. キャッシュ戦略の判断フローチャート

「このリソースにはどのCache-Controlを設定すべきか?」を判断するフローチャートです。

08_cache_decision_tree.png

判断のポイント

  1. 機密データか?no-store で一切キャッシュしない
  2. CDNに載せてよいか? → ユーザー固有なら private
  3. コンテンツは変わるか? → 不変なら長期キャッシュ、変わるなら no-cache で都度検証

6. リソース別キャッシュ設定ガイド

実務でよく使うリソースごとの推奨設定をまとめます。

08_cache_strategy_table.png

Nginxでの設定例

# 静的アセット(ハッシュ付きファイル名)
location ~* \.(js|css)$ {
    add_header Cache-Control "public, max-age=31536000, immutable";
}

# 画像
location ~* \.(png|jpg|gif|svg|webp)$ {
    add_header Cache-Control "public, max-age=86400";
}

# HTMLページ
location ~* \.html$ {
    add_header Cache-Control "no-cache";
    etag on;
}

# API
location /api/ {
    add_header Cache-Control "private, max-age=0, must-revalidate";
    etag on;
}

キャッシュバスティング

「長期キャッシュを設定したのに、ファイルを更新したい」場合は キャッシュバスティング を使います。

<!-- ファイル名にハッシュを含める(推奨) -->
<script src="/js/app.a1b2c3d4.js"></script>
<link rel="stylesheet" href="/css/style.e5f6g7h8.css">

<!-- ビルドツール(Vite, webpack等)が自動でハッシュを付与 -->

ファイルの内容が変われば ハッシュが変わる → URLが変わる → ブラウザは新しいファイルとして取得 します。これにより、max-age=31536000(1年)のキャッシュを安全に設定できます。


7. よくある落とし穴

① CDNにユーザー固有データがキャッシュされる

# 危険: ユーザー固有のAPIレスポンスにpublicを設定
Cache-Control: public, max-age=3600

# 安全: privateを指定
Cache-Control: private, max-age=0, must-revalidate

② no-cache と no-store の混同

# 「キャッシュして検証」(HTMLページ向け)
Cache-Control: no-cache

# 「一切キャッシュしない」(機密データ向け)
Cache-Control: no-store

③ Service Workerのキャッシュを忘れる

ブラウザキャッシュとは別に、Service Worker が独自にキャッシュを持つことがあります。Cache-Controlだけでなく、Service Workerのキャッシュ戦略も合わせて設計してください。


8. まとめ

項目 ポイント
キャッシュの目的 同じデータの再取得を避け、表示速度とサーバー負荷を改善
3つのレイヤー ブラウザキャッシュ → CDNキャッシュ → サーバーキャッシュ
Cache-Control キャッシュの動作を制御する最重要ヘッダー
public / private CDNにキャッシュさせるか、ブラウザ限定か
no-cache / no-store 毎回検証 / 一切保存しない(名前に注意)
ETag / Last-Modified 条件付きリクエストで304応答を活用し、転送量を削減
キャッシュバスティング ハッシュ付きファイル名で長期キャッシュと更新を両立

次回予告

第9回では 「CORS ― クロスオリジンの壁を理解する」 を図解で解説します。「なぜフロントエンドからAPIを叩くとエラーになるのか?」というWeb開発最大の罠を攻略します。


シリーズ目次

# テーマ
1 HTTPリクエスト/レスポンスの仕組み
2 Cookie・Session・JWTの違い
3 OAuth 2.0 の仕組み
4 DNS解決の流れ
5 HTTPS・TLS通信の仕組み
6 CDN の仕組みと役割
7 WebSocket ― 双方向リアルタイム通信
8 キャッシュ戦略(ブラウザ・サーバー・CDN)(この記事)
9 CORS ― クロスオリジンの壁を理解する
10 REST API 設計の基本原則

「この記事が役に立った」と思ったら、LGTM とストックをお願いします。

@kotaro_ai_lab
AI活用や開発効率化について発信しています。フォローお気軽にどうぞ!

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?