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