HTTP キャッシュについて: 強力なキャッシュ vs ネゴシエートされたキャッシュ
Grace Collins
Solutions Engineer · Leapcell

ブラウザのキャッシュの仕組み
ブラウザでウェブページを開くと、入力された URL に基づいてブラウザが対応するサーバーにリクエストを送信し、必要なデータリソースを取得することは誰もが知っています。ただし、この過程で、ページが読み込まれるまでに時間がかかり(白い画面が表示される)、画面にレンダリングされることがあります。
ユーザーエクスペリエンスを向上させるために、DNS キャッシュ、CDN キャッシュ、ブラウザキャッシュ、ローカルページキャッシュなど、さまざまなキャッシュ技術が不可欠になります。優れたキャッシュ戦略は、冗長なリソースリクエストを削減し、サーバーのオーバーヘッドを削減し、ページの読み込み速度を向上させることができます。
この記事では、HTTP の強力なキャッシュとネゴシエートされたキャッシュに焦点を当てます。
基本原則
ブラウザがリソースをロードするとき、まず Expires および Cache-Control リクエストヘッダーを調べて、強力なキャッシュ戦略を適用するかどうかを判断します。これにより、ブラウザがリモートサーバーからリソースを要求するか、ローカルキャッシュからリソースを取得するかを決定します。
強力なキャッシュ
ブラウザでは、強力なキャッシュは Expires(HTTP/1.0 仕様で定義)と Cache-Control(HTTP/1.1 で定義)の 2 つのカテゴリに分けられます。
Expires
Expires は HTTP/1.0 の標準であり、リソースの有効期限を示す応答ヘッダーフィールドとして使用されます。値は絶対タイムスタンプで、サーバーから返されます。
- ブラウザが最初にリソースを要求すると、サーバーの応答ヘッダーに
Expiresフィールドが含まれます。 - 次回ブラウザが同じリソースを要求すると、以前の応答から
Expiresの値を確認します。 - 現在のリクエスト時刻が
Expiresで指定された有効期限より前の場合は、ブラウザはキャッシュされたリソースを直接使用します。
ただし、Expires はローカルシステムの時刻に依存しているため、クライアントとサーバーのクロックのずれにより、キャッシュの不整合が発生する可能性があります。
Cache-Control
前述のように、Expires には欠点があります。クライアントのローカル時刻がサーバーの時刻と異なる場合、キャッシュの精度に影響を与える可能性があります。この問題に対処するために、HTTP/1.1 では Cache-Control フィールドが導入されました。これは Expires よりも優先されます。Expires とは異なり、Cache-Control は絶対タイムスタンプではなく、相対時間を使用してキャッシュの有効期限を定義します。
最も一般的な Cache-Control ディレクティブには、次のものがあります。
max-age: リソースが新鮮な状態を維持する秒数(例:3600)(つまり、現在の時刻 + 3600 秒)を指定します。s-maxage:max-ageと同様ですが、特にプロキシサーバーでのキャッシュ用です。private: リソースはプライベートキャッシュ(つまり、クライアントによるキャッシュですが、プロキシサーバーなどの共有キャッシュではありません)によってのみキャッシュできます。public: リソースはクライアントとプロキシサーバーの両方でキャッシュできます。no-store: あらゆる種類のキャッシュを防止します。no-cache: リソースはローカルキャッシュに保存されますが、クライアントに提供する前にオリジンサーバーで再検証する必要があります。
ネゴシエートされたキャッシュ
強力なキャッシュは、ブラウザのみによって決定されます。強力なキャッシュがヒットしない場合、ブラウザはサーバーにリクエストを送信して、ネゴシエートされたキャッシュが適用されるかどうかを確認します。キャッシュが有効な場合、サーバーは新しいリソースデータではなく、304 Not Modified ステータスを返します。
ネゴシエートされたキャッシュ(条件付きキャッシュとも呼ばれます)は、サーバーによって決定され、2 組のペアのヘッダーが関係します。ブラウザが最初のリクエストを行うと、サーバーは応答に Last-Modified または ETag ヘッダーのいずれかを含めます。後続のリクエストには、対応するリクエストヘッダー(If-Modified-Since または If-None-Match)が含まれて、リソースが変更されたかどうかを判断します。
Last-Modified: リソースの最終変更時刻を示し、サーバーから返されます。If-Modified-Since: ブラウザからリクエストで送信され、以前のLast-Modified値が含まれています。ETag: リソースの一意の識別子。リソースが変更されると、ETagの値もそれに応じて変更されます。ファイルの内容が同じままであっても変更される可能性があるLast-Modifiedとは異なり、ETagはより正確なキャッシュ検証を保証します。If-None-Match: ブラウザからリクエストで送信され、以前に返されたETag値が含まれています。
強力なキャッシュとリクエストフロー
- ブラウザがリソースを要求すると、最初にローカルキャッシュレコードがあるかどうかを確認します。レコードが存在しない場合は、サーバーにリクエストを送信し、返された
Last-Modifiedの値を保存します。 - キャッシュレコードが存在する場合、ブラウザは最初に強力なキャッシュがまだ有効かどうかを確認します(
Cache-ControlはExpiresよりも優先されます)。キャッシュがまだ有効な場合、ブラウザはキャッシュされたリソースを提供します(HTTP ステータス 200)。 - 強力なキャッシュの有効期限が切れている場合、ブラウザはネゴシエートされたキャッシュ戦略を使用してリクエストを開始します。サーバーは最初に
ETagの値を確認します。- クライアントの
ETagがサーバーのETagと一致する場合、サーバーは 304 Not Modified を返します(リソースデータを送信せずに)。
- クライアントの
- サーバーが
ETagを使用しない場合は、If-Modified-Sinceを確認します。指定された値がサーバーの最終変更時刻と一致する場合、サーバーは 304 Not Modified を返します。 ETagもIf-Modified-Sinceも一致しない場合、サーバーは新しいリソースを送信し、キャッシュを更新します。
ETag が必要な理由
ETag は、Last-Modified の問題に対処するために導入されました。これには次のものが含まれます。
- タイムスタンプの不正確さ: コンテンツが同じままであっても、ファイルの最終変更タイムスタンプが変更される可能性があり、不要なキャッシュの無効化につながります。
- 高頻度の変更:
Last-Modifiedは秒レベルの粒度のみをサポートしており、頻繁に更新されるファイルには十分でない場合があります。ETagはより優れた精度を保証します。 - 一部のサーバーはファイルの最終変更時刻を正確に判断できないため、
ETagがより良い代替手段となります。
HTTP ステータスコードの違い
200: リクエストが成功し、サーバーはリソースの新しいコピーを返します。200 (from memory cache / from disk cache): 強力なキャッシュがまだ有効であるため、ブラウザはローカルキャッシュからリソースをロードします。304 Not Modified: リクエストはネゴシエートされたキャッシュを使用し、サーバーはキャッシュされたリソースがまだ有効であると判断しました。
注:
from memory cache: リソースはメモリから取得されました(例:ソフトリフレッシュ後)。from disk cache: リソースはディスクストレージから取得されました(例:ブラウザタブを再度開いた後)。
キャッシュの優先順位ルール
ExpiresとCache-Controlの両方が存在する場合、Cache-Controlが優先されます。- Cache-Control > Expires
- 強力なキャッシュとネゴシエートされたキャッシュの両方が存在する場合、ブラウザは最初に強力なキャッシュを確認します。キャッシュがまだ有効な場合は、それが使用されます。それ以外の場合は、ネゴシエートされたキャッシュが適用されます。
- 強力なキャッシュ > ネゴシエートされたキャッシュ
ETagとLast-Modifiedの両方が存在する場合、ETagが優先されます。- ETag > Last-Modified
追加の注意点
HTTP/1.0 仕様には、Pragma と呼ばれる古いキャッシュディレクティブがあり、Cache-Control: no-cache と同じ効果があり、ブラウザにオリジンサーバーでリソースを再検証させます。
キャッシュの優先順位の順序:
Pragma -> Cache-Control -> Expires -> ETag -> Last-Modified
ヒューリスティックキャッシュ
応答に Expires または Cache-Control ヘッダーが含まれていないが、Last-Modified が含まれている場合、ブラウザはヒューリスティックキャッシュ戦略を適用します。
ブラウザで使用される式は次のとおりです。
(currentTime - lastModified) * 0.1
このキャッシュ戦略は、サーバーがキャッシュポリシーを明示的に定義していない場合にのみ適用されます。
詳細については、HTTP ヒューリスティックキャッシュ (Cache-Control および Expires ヘッダーがない場合) の説明 を参照してください。
その他の考慮事項
- ネゴシエートされたキャッシュは、強力なキャッシュと組み合わせて使用する場合にのみ有効です。強力なキャッシュがない場合、ネゴシエートされたキャッシュには意味がありません。
- ほとんどの Web サーバーは、ネゴシエートされたキャッシュをデフォルトで有効にしており、通常は
Last-ModifiedとETagの両方を同時に使用します。
重要なシナリオ
- 分散システムでは、
Last-Modifiedタイムスタンプがサーバー間で一貫していることを確認してください。そうしないと、ロードバランシングによってキャッシュの検証に矛盾が生じ、リソースの不要な再フェッチにつながる可能性があります。 - 分散システムでは、異なるサーバーが異なる
ETag値を生成し、不要なキャッシュミスを引き起こす可能性があるため、ETagを無効にすることをお勧めします。
Leapcell は、バックエンドプロジェクトをホストするための最高の選択肢です。
Leapcell は、Web ホスティング、非同期タスク、および Redis の次世代サーバーレスプラットフォームです。
多言語サポート
- Node.js、Python、Go、または Rust で開発します。
無制限のプロジェクトを無料でデプロイ
- 使用量に対してのみ支払い — リクエストも料金もありません。
最高の費用対効果
- アイドル料金なしの従量課金制。
- 例:25 ドルで平均応答時間 60 ミリ秒で 694 万件のリクエストをサポートします。
合理化された開発者エクスペリエンス
- 簡単なセットアップのための直感的な UI。
- 完全に自動化された CI/CD パイプラインと GitOps 統合。
- 実用的な洞察のためのリアルタイムのメトリックとロギング。
簡単なスケーラビリティと高いパフォーマンス
- 簡単な自動スケーリングで、高い同時実行性を処理します。
- 運用上のオーバーヘッドはゼロ — 構築に集中するだけです。
詳細については、ドキュメントをご覧ください。
X でフォローしてください: @LeapcellHQ



