HTTPキャッシュの解説:ETag、Cache-Control、CDN

Web2026-09-28TryQuickToolBox

なぜあなたのウェブサイトは遅く感じるのか(そしてキャッシュがそれをどう解決するか)

画像を最適化し、CSSを圧縮し、サーバーまでアップグレードした。それなのに、リピーターの読み込み時間は依然として遅く、オリジンサーバーは帯域幅を消費している。原因は? 非効率なHTTPキャッシュです。適切なキャッシュヘッダーがなければ、ブラウザは訪問のたびに同じアセットを再ダウンロードし、CDNも効果的に機能できません。

HTTPキャッシュは、利用可能な中で最も効果の高いパフォーマンス最適化の1つです。レイテンシを削減し、帯域幅コストを抑え、オリジンサーバーの負荷を軽減します。このガイドでは、主要なメカニズムであるETag、Cache-Control、そしてCDNがどのように関わるかを解説します。正しく実装するための実践的な戦略を学べます。

HTTPキャッシュの仕組み:全体像

ブラウザがリソースをリクエストすると、オリジンサーバーから取得するか、ローカルに保存されたコピーを提供するかを選択できます。HTTPキャッシュは、保存されたコピーがいつ新鮮と見なされ、いつ再検証が必要かを定義するルールです。

主なキャッシュの種類は2つあります:

どちらもHTTPヘッダーに依存して、新鮮さと再検証を決定します。最も重要な2つのヘッダーはCache-ControlとETagです。

Cache-Control:新鮮さのルール

Cache-Controlは、キャッシュポリシーを定義する主要なヘッダーです。これはディレクティブベースのヘッダーで、キャッシュにレスポンスの扱い方を指示します。

主要なディレクティブ

例:Cache-Control: public, max-age=31536000, immutableは、ハッシュ化されたファイル名を持つ静的アセットに最適です。

ETagと条件付きリクエスト

ETag(エンティティタグ)は、リソースの特定のバージョンの識別子です。リソースが変更されると、ETagも変わります。ブラウザはETagを使用して条件付きリクエストを行います:保存されたETagをIf-None-Matchヘッダーで送信します。リソースが変更されていなければ、サーバーは304 Not Modifiedをボディなしで返し、帯域幅を節約します。

同様に、Last-ModifiedはIf-Modified-Sinceと連携しますが、ETagの方がより正確です(同じ秒内の変更も検出できます)。

ETagの生成方法

ほとんどのウェブサーバーとフレームワークはETagを自動生成します。例えば、Express.jsではapp.set('etag', 'strong')で有効にできます。Nginxでは、静的ファイルに対してデフォルトでETagが有効です。

強力なETag(例:"abc123")はバイト単位での同一性を保証します。弱いETag(例:W/"abc123")は意味的な等価性を示し、正確なバイトを保証しません。

CDNキャッシュ:大規模な共有キャッシュ

CDN(コンテンツデリバリネットワーク)は、グローバルに分散された共有キャッシュとして機能します。エッジロケーションでコンテンツをキャッシュし、ユーザーに近い拠点から配信します。これによりレイテンシが減り、オリジンの負荷が軽減されます。

CDNはCache-Controlヘッダーを尊重しますが、多くの場合独自の設定を持っています。主な概念:

CDNを使用する場合、Cache-Controlにs-maxageを設定して、ブラウザキャッシュとは別に共有キャッシュの新鮮さを制御します。例えば:Cache-Control: public, max-age=600, s-maxage=3600は、ブラウザは10分間キャッシュし、CDNは1時間キャッシュすることを意味します。

キャッシュヘッダーの比較

ヘッダー 目的 例
Cache-Control 新鮮さとキャッシュルールを定義 public, max-age=3600
ETag リソースバージョンの一意の識別子 "abc123"
Last-Modified 最終変更のタイムスタンプ Wed, 21 Oct 2025 07:28:00 GMT
Expires レガシーな絶対有効期限 Wed, 21 Oct 2025 07:28:00 GMT
Vary キャッシュに影響するヘッダーを指定 Accept-Encoding

注:ExpiresはCache-Controlに取って代わられましたが、古いクライアントではまだ使用されています。

ウェブアプリのための実践的なキャッシュ戦略

効果的なキャッシュを実装するには、次の手順に従ってください:

  1. 静的アセットにフィンガープリントを付ける: ハッシュ化されたファイル名(例:app.a1b2c3.js)を使用し、長いmax-ageとimmutableを設定します。ファイルが変更されるとハッシュが変わり、キャッシュが更新されます。
  2. HTMLに適切なCache-Controlを設定する: HTMLは通常no-cacheまたは短いmax-ageにして、ユーザーがすぐに更新を受け取れるようにします。再検証にはETagを使用します。
  3. Vary: Accept-Encodingを使用する: 圧縮版と非圧縮版を配信する場合、これによりキャッシュが別々に保存します。
  4. s-maxageでCDNを活用する: 共有キャッシュには長めのs-maxageを設定してオリジンの負荷を減らし、必要に応じてブラウザキャッシュは短く保ちます。
  5. 賢く無効化する: 重要な更新をデプロイするときはCDNのパージAPIを使用します。静的アセットでは、フィンガープリントによりパージの必要がなくなります。
  6. キャッシュヒット率を監視する: CDNの分析を使用して、キャッシュが効果的であることを確認します。ヒット率が低い場合は、ヘッダーの設定ミスを示しています。

よくある落とし穴と回避方法

キャッシュ設定のテスト

ブラウザのDevTools(ネットワークタブ)を使用してレスポンスヘッダーを検査し、リソースがキャッシュから提供されているか(「(from disk cache)」または「(from memory cache)」を探す)を確認します。CDNの動作については、curl -Iを使用してX-CacheやCF-Cache-Statusなどのヘッダーを確認します。WebPageTestなどのツールは、訪問間のキャッシュを視覚化できます。

FAQ

ETagとLast-Modifiedの違いは何ですか?

ETagはリソースが変更されると変わる不透明な識別子で、Last-Modifiedはタイムスタンプです。ETagは同じ秒内の変更も検出でき、クロック同期に依存しないため、より正確です。

no-cacheとno-storeはいつ使うべきですか?

キャッシュにレスポンスを保存させたいが、使用前に毎回オリジンで再検証したい場合はno-cacheを使用します。どのキャッシュにもディスクやメモリに書き込まれてはならない機密データにはno-storeを使用します。

CDNはキャッシュ無効化をどのように処理しますか?

CDNは、特定のURLやディレクトリ全体をエッジキャッシュから削除できるパージAPIを提供します。ソフトパージをサポートし、コンテンツを古いものとしてマークし、次のリクエストで再検証するものもあります。アセットのフィンガープリントは、パージよりも効率的なことが多いです。

結論

ETag、Cache-Control、CDNを使ったHTTPキャッシュをマスターすることは、高速でスケーラブルなウェブアプリケーションを構築するために不可欠です。静的アセットとHTMLに適切なヘッダーを設定することから始め、s-maxageでCDNの共有キャッシュを活用し、常に設定をテストしましょう。キャッシュヘッダーの小さな変更が、大きなパフォーマンス向上につながります。

サーバーログをすばやく分析してキャッシュヒット率を確認したいですか? Nginx Log Analyzerを使ってアクセスログを解析・可視化しましょう。