メインコンテンツまでスキップ

13. Caching in HTTP (HTTPキャッシング)

HTTPは通常、分散情報システムで使用されます。このシステムでは、レスポンスキャッシュを使用することでパフォーマンスを向上させることができます。HTTP/1.1プロトコルには、キャッシュが可能な限り適切に機能するように設計された多くの要素が含まれています。HTTP/1.1のキャッシングの目標は、多くの場合にリクエストを送信する必要性を排除し、他の多くの場合に完全なレスポンスを送信する必要性を排除することです。前者は、多くの操作に必要なネットワーク往復の数を削減します。この目的のために「有効期限」(expiration) メカニズムを使用します(セクション13.2を参照)。後者は、ネットワーク帯域幅の要件を削減します。この目的のために「検証」(validation) メカニズムを使用します(セクション13.3を参照)。

HTTP/1.1プロトコルは、以下の重要な要素を提供します:

  1. すべての当事者が必要とする場合に完全な意味的透過性を提供するプロトコル機能
  2. オリジンサーバーまたはユーザーエージェントが非透過的操作を明示的に要求および制御できるプロトコル機能
  3. キャッシュが、要求された意味的透過性の近似を維持しないレスポンスに警告を添付できるプロトコル機能

13.1.1 Cache Correctness (キャッシュの正確性)

正しいキャッシュは、リクエストに適用可能で、以下の条件のいずれかを満たす、キャッシュが保持する最新のレスポンスを使用してリクエストに応答しなければなりません (MUST):

  1. オリジンサーバーとのレスポンスの再検証によって、オリジンサーバーが返すものとの等価性がチェックされている(セクション13.3)

  2. 「十分に新鮮」(fresh enough) である(セクション13.2を参照)。デフォルトでは、これはクライアント、オリジンサーバー、およびキャッシュの最も制限の少ない鮮度要件を満たすことを意味します(セクション14.9を参照)

  3. 適切な304 (Not Modified)、305 (Proxy Redirect)、またはエラー (4xxまたは5xx) レスポンスメッセージである

キャッシュがオリジンサーバーと通信できない場合、正しいキャッシュは、レスポンスがキャッシュから正しく提供できる場合は上記のように応答すべき (SHOULD) です。できない場合は、通信失敗を示すエラーまたは警告を返さなければなりません (MUST)。

13.1.2 Warnings (警告)

キャッシュが第一手でも「十分に新鮮」でもないレスポンスを返す場合は常に、この効果のためにWarning一般ヘッダを使用して警告を添付しなければなりません (MUST)。警告には3桁の警告コードが割り当てられます:

  • 1xx - レスポンスの鮮度または再検証ステータスを記述する警告で、成功した再検証後に削除する必要があります
  • 2xx - 再検証によって修正されないエンティティボディまたはエンティティヘッダの何らかの側面を記述する警告で、成功した再検証後に削除してはなりません

13.1.3 Cache-control Mechanisms (キャッシュ制御メカニズム)

HTTP/1.1の基本的なキャッシュメカニズム(サーバー指定の有効期限と検証器)は、キャッシュへの暗黙的な指示です。Cache-Controlヘッダは、クライアントまたはサーバーがリクエストまたはレスポンスでさまざまな指令を送信できるようにします。これらの指令は通常、デフォルトのキャッシュアルゴリズムをオーバーライドします。

13.1.4 Explicit User Agent Warnings (明示的なユーザーエージェント警告)

多くのユーザーエージェントには、「戻る」ボタンや履歴リストなどの履歴リストメカニズムがあり、ユーザーが最近取得したエンティティを再表示するために使用できます。履歴メカニズムとキャッシュは異なります。

13.1.5 Exceptions to the Rules and Warnings (ルールと警告の例外)

特定の状況では、オペレーターは、HTTP/1.1ルールに準拠していない場合でも、古いレスポンスを返すようにキャッシュを構成することを選択します。このような状況には以下が含まれますが、これらに限定されません:

  • オリジンサーバーにアクセスできない場合に古いデータを返す
  • ネットワーク接続が遅いまたは信頼できない場合
  • 特定の時間帯により高速なレスポンス時間を提供する場合

13.1.6 Client-controlled Behavior (クライアント制御の動作)

ユーザーエージェントには通常、以前に取得した表現を再表示するために使用できる、戻るボタンなどの履歴メカニズムがあります。

13.2 Expiration Model (有効期限モデル)

HTTPキャッシュは通常、オリジンサーバーに問い合わせることなく使用できる時間までキャッシュエントリを保存します。キャッシュの使用がリクエストクライアントまたはオリジンサーバーのいずれにも見えない場合、「意味的に透過的」という用語を使用します。

13.2.1 Server-Specified Expiration (サーバー指定の有効期限)

HTTPキャッシュプロトコルは、レスポンスがいつ古くなるかを示すために明示的な有効期限を使用します。有効期限メカニズムは、以下のように定義されたレスポンスにのみ適用されます:

  • 200、203、206、300、301、または410レスポンスへのレスポンス
  • Cache-Controlヘッダフィールドが明示的にキャッシュを許可しているレスポンス

13.2.2 Heuristic Expiration (ヒューリスティック有効期限)

オリジンサーバーが常に明示的な有効期限を提供するわけではないため、HTTPキャッシュは通常、キャッシュエントリの他のヘッダ値(Last-Modified時刻など)を使用するアルゴリズムを使用して、ヒューリスティック有効期限を割り当てます。

13.2.3 Age Calculations (経過時間計算)

レスポンスが新鮮かどうかを知るために、キャッシュはその経過時間 (age) を知る必要があります。Ageの値は、レスポンスが生成または正常に検証された後の時間の推定値です。

経過時間計算式:

age_value = now - date_value
apparent_age = max(0, response_time - date_value)
corrected_received_age = max(apparent_age, age_value)
response_delay = response_time - request_time
corrected_initial_age = corrected_received_age + response_delay
resident_time = now - response_time
current_age = corrected_initial_age + resident_time

13.2.4 Expiration Calculations (有効期限計算)

レスポンスが新鮮かどうかを判断するために、現在の経過時間を鮮度ライフタイムと比較します。レスポンスは、その経過時間が鮮度ライフタイムを超えていない場合に新鮮です。

鮮度ライフタイム計算:

freshness_lifetime = max_age_value
または
freshness_lifetime = expires_value - date_value
または
freshness_lifetime = (now - last_modified_value) * 0.1

13.2.5 Disambiguating Expiration Values (有効期限値の曖昧さ解消)

有効期限と現在時刻の比較は時刻のずれに敏感なため、実装は最も保守的な有効期限を使用すべきです。

13.2.6 Disambiguating Multiple Responses (複数のレスポンスの曖昧さ解消)

クライアントが複数のパスを介してリソースにアクセスしている可能性があるため、キャッシュは同じリソースに対する複数のレスポンスを受信する場合があります。キャッシュは最新のレスポンスを使用すべきです。

13.3 Validation Model (検証モデル)

キャッシュに古いキャッシュエントリがあり、それを使用したい場合、最初にオリジンサーバーと(または新鮮なエントリを持つキャッシュを介して)チェックして、そのキャッシュエントリがまだ使用可能かどうかを確認する必要があります。これを、キャッシュエントリの「検証」と呼びます。

13.3.1 Last-Modified Dates (最終変更日)

Last-Modifiedエンティティヘッダフィールド値は、通常、キャッシュバリデータとして使用されます。通常、キャッシュエントリのLast-Modified値はIf-Modified-Sinceリクエストヘッダとともに送信されます。

13.3.2 Entity Tag Cache Validators (エンティティタグキャッシュバリデータ)

ETagレスポンスヘッダフィールド値(エンティティタグ)は、「不透明な」キャッシュバリデータを提供します。これにより、特に以下の場合により信頼性の高い検証が可能になります:

  • 変更日を便利に保存できない場合
  • ドキュメントの変更日のHTTP日付値の1秒の分解能では不十分な場合
  • 変更日が一貫していない場合

13.3.3 Weak and Strong Validators (弱いバリデータと強いバリデータ)

オリジンサーバーとキャッシュの目標が異なる場合があるため、クライアントは絶対最新のコピーではなく、十分に良いレスポンスのみを必要とすることがあります。

  • 強いバリデータ - エンティティが変更されるたびに変更され、その変更が重要かどうかに関係なく変更される
  • 弱いバリデータ - すべてのエンティティ変更に対して変更されない可能性があります(プレフィックス "W/")

13.3.4 Rules for When to Use Entity Tags and Last-Modified Dates (エンティティタグと最終変更日を使用する場合のルール)

HTTP/1.1オリジンサーバーは、Last-Modified値の代わりに、またはそれに加えて、可能な限りエンティティタグバリデータを送信すべき (SHOULD) です。

13.3.5 Non-validating Conditionals (非検証条件)

条件付きリクエストは、リクエストの最適化や更新の損失の防止など、他の目的にも使用できます。

13.4 Response Cacheability (レスポンスのキャッシュ可能性)

特に指示がない限り、GETを使用して取得されたレスポンスはキャッシュ可能です。以下のルールは、レスポンスがいつキャッシュ可能かを定義します:

  1. リクエストメソッド自体がキャッシュ可能である(GETおよびHEAD)
  2. レスポンスステータスコードが理解可能でキャッシュ可能である(200、203、204、206、300、301、404、405、410、414、501)
  3. Cache-Controlヘッダがキャッシュを禁止していない
  4. 共有キャッシュを使用している場合、Cache-Controlが明示的に許可しない限り、Authorizationヘッダが存在しない

13.5 Constructing Responses From Caches (キャッシュからのレスポンス構築)

13.5.1 End-to-end and Hop-by-hop Headers (エンドツーエンドヘッダとホップバイホップヘッダ)

HTTPヘッダフィールドは、エンドツーエンド (end-to-end) ヘッダとホップバイホップ (hop-by-hop) ヘッダに分類されます:

  • エンドツーエンドヘッダ - 最終受信者に送信する必要があります
  • ホップバイホップヘッダ - 単一のトランスポートレベル接続にのみ意味があります

13.5.2 Non-modifiable Headers (変更不可能なヘッダ)

一部の機能では、キャッシュが特定のキャッシュエントリのヘッダを変更する必要がある場合があります。エンドツーエンドヘッダのみを変更できます。

13.5.3 Combining Headers (ヘッダの結合)

キャッシュがリクエストに対するレスポンスを検証し、レスポンスに一部のヘッダフィールドが含まれているが他のヘッダフィールドが含まれていない場合、キャッシュは新しいフィールドを古いエントリのフィールドと結合する必要があります。

13.5.4 Combining Byte Ranges (バイト範囲の結合)

キャッシュからのレスポンスは、部分的なコンテンツレスポンスである可能性があります。場合によっては、キャッシュは格納されたバイト範囲のセットと新しいバイト範囲を結合してリクエストを満たすことができます。

13.6 Caching Negotiated Responses (ネゴシエートされたレスポンスのキャッシング)

サーバー駆動のコンテンツネゴシエーション(セクション12.1)を使用すると、リクエストの特定のヘッダフィールドの値に基づいて異なるレスポンスが作成される場合があります。Varyヘッダフィールドは、選択に使用されるリクエストヘッダフィールドを示すために使用されます。

13.7 Shared and Non-Shared Caches (共有キャッシュと非共有キャッシュ)

一部のヘッダフィールドの目的と制限は、さまざまなタイプのキャッシュで異なるため、以下を区別します:

  • 非共有キャッシュ - 単一のユーザーのみがアクセスできるキャッシュ(例:ユーザーエージェントキャッシュ)
  • 共有キャッシュ - 複数のユーザーがアクセスできるキャッシュ(例:プロキシキャッシュ)

13.8 Errors or Incomplete Response Cache Behavior (エラーまたは不完全なレスポンスキャッシュの動作)

キャッシュが不完全なレスポンス(例:Content-Lengthバイトが指定されたバイト数より少ない)を受信した場合、不完全なレスポンスを保存できます (MAY)。ただし、キャッシュはそれを部分的なレスポンスとして扱わなければなりません (MUST)。

13.9 Side Effects of GET and HEAD (GETとHEADの副作用)

オリジンサーバーがレスポンスのキャッシングを明示的に禁止しない限り、GETおよびHEADメソッドのアプリケーションは副作用を持つべきではありません (SHOULD)。

13.10 Invalidation After Updates or Deletions (更新または削除後の無効化)

状態を変更する(POST、PUT、DELETE)メソッドの正常な実行により、そのRequest-URIで識別されるリソースのすべてのキャッシュエントリを無効にする必要があります。

13.11 Write-Through Mandatory (書き込み貫通必須)

オリジンサーバーでリソースを変更するすべてのメソッドは、オリジンサーバーに書き込み貫通しなければなりません (MUST)。現在の仕様では、他の場所でこのようなレスポンスをキャッシュする方法は定義されていません。

13.12 Cache Replacement (キャッシュ置換)

キャッシュが、古いエントリを新しいエントリで置き換えるレスポンスを受信し、古いエントリに任意のCache-Control指令が含まれている場合、キャッシュはこれらの指令に従うべき (SHOULD) です。

13.13 History Lists (履歴リスト)

ユーザーエージェントには通常、「戻る」ボタンや履歴リストなどの履歴メカニズムがあり、ユーザーセッション中に以前に取得した表現を再表示するために使用できます。

履歴メカニズムの要件:

  1. 履歴メカニズムは、ユーザーの好みに応じて以前に取得したリソースを表示すべき (SHOULD) です
  2. 履歴メカニズムは、リソースを検証しようとすべきではありません (SHOULD NOT)
  3. 履歴メカニズムは、現在期限切れであっても、以前に取得した表現を表示すべき (SHOULD) です

重要な注意事項:この章では、有効期限モデル、検証モデル、キャッシュ制御などのコアコンセプトを含む、HTTP/1.1のキャッシングメカニズムについて詳しく説明しています。キャッシングはHTTPパフォーマンスを向上させるための重要なメカニズムであり、これらのコンセプトを理解することは、高性能なWebアプリケーションを構築する上で不可欠です。