同じ案内ページを何度も配信するとき、HTTPのキャッシュは保存済みの応答を再利用して、通信とサーバーの仕事を減らします。応答にCache-Control: max-age=60とあれば、受け取ってから60秒間はそのまま使えるようにも見えます。しかし、途中のキャッシュで既に時間が経っているなら、受信した側に残る時間は60秒より短くなります。
その経過を読み取る手がかりがAgeです。HTTPのキャッシュ規格RFC 9111に沿って、応答の年齢と有効期間を分け、上流で40秒経過した応答が届く例を計算します。
簡単にまとめると?
- Ageは、元のサーバーで応答が生成または検証されてからの経過時間の推定値です。ファイルを最後に編集してからの時間とは違います。
- 受信時の年齢には、上流で過ごした時間や通信の遅れを反映します。保存先が変わっても、有効期間が毎回最初から始まるわけではありません。
- 有効期間60秒、現在の年齢52秒なら、鮮度の境界まで残るのは8秒です。鮮度が残っていることだけで、あらゆる要求に再利用できるとは限りません。
有効期間と年齢は、比べるための別の値
HTTPの「fresh」は、応答の本文が世界の最新情報と必ず一致している、という意味ではありません。キャッシュ規則に基づいて、鮮度が保たれていると判断される状態です。生成後に元のデータが変わっていても、有効期間の途中では保存済みの応答を使う場合があります。
判断には二つの値を使います。一つはfreshness lifetime、つまり鮮度を保つと定められた期間。もう一つはcurrent age、つまり保存中の応答について見積もった現在の年齢です。期間が年齢より長い間はfreshで、同じ値に達するとstaleになります。staleは、この鮮度の条件を満たさなくなった状態を指します。[1]
以下では、対象のキャッシュに適用される有効期間がmax-ageで指定された60秒であり、保存や要求との照合に関するほかの条件も満たしていると仮定します。共有キャッシュ向けのs-maxageなど、別の指定が優先される場面はこの例に含めません。
受け取ったAgeに、通信と保存中の時間を加える
あるキャッシュが上流へ要求を送り、応答を受け取る場面を考えます。計算を見やすくするため、時刻は同じ基準から測った秒数とし、時計のずれはないものとします。実際の通信では、Dateは日時、Ageは秒数として表されます。
- 要求を送った時刻:100秒
- 応答を受け取った時刻:102秒
- 応答のDateが示す時刻:95秒
- 受け取ったAge:40秒
Dateだけを見れば、受信時には102−95=7秒が過ぎています。一方、Ageには上流のキャッシュなどでの経過が反映されています。要求から受信までの2秒をAgeに加えた補正値は、40+2=42秒です。Dateからの7秒だけを使うと、上流から伝わった経過時間を過小評価することになります。
RFC 9111は、Ageに応答の遅れを加えた値を受信時の年齢として使うことを認めています。また、Ageを正しく挿入しない古いキャッシュが混じる場合には、Dateから求めた値と比べて大きい方を取る、より保守的な計算を示しています。すべての実装が常に大きい方を取らなければならない、という規定ではありません。この例ではどちらの方法でも42秒になります。[1]
さらに、その応答を受信後10秒間保存し、時刻112秒で使うとします。現在の年齢は42+10=52秒です。max-age=60なら、鮮度の境界に達するまで残る時間は60−52=8秒になります。

受信した時点をゼロとして数え直すと、時刻112秒では10秒しか経っていないように見え、残りを50秒と誤認します。途中にキャッシュが増えるたびに期間を延ばさないよう、上流まで含めた年齢を引き継ぐことが必要です。
Ageがないときも、受信直後だから新しいとは決めない
Ageが欠けている場合、規格の計算では受け取ったAgeの値を0として扱います。ただし、それだけで現在の年齢が常に0になるわけではありません。応答の遅れやDateを使った見積もり、受信後に保存していた時間は別にあります。
たとえば同じ時刻条件でAgeだけがなければ、Ageに応答の遅れを加えた値は2秒、Dateからの値は7秒です。先ほどの保守的な方法なら受信時の年齢は7秒になります。これは「Ageがないなら必ず7秒」という一般則ではなく、示した条件と計算方法による結果です。
RFC 9111は、Ageが存在しないことから、今回の要求が元のサーバーまで到達したとは判断できない、と説明しています。逆にAgeの値を見ても、それをファイルの最終更新からの経過時間へ読み替えることはできません。応答の生成・検証と、資源そのものの編集は別の出来事です。[1]
境界を越えた後は、別の規則を確認する
例の年齢が60秒に達すると、freshness lifetimeより小さいという条件を満たさなくなります。しかし、staleになった瞬間に本文を必ず削除する、という意味ではありません。再検証に使うため保存を続けることもありますし、古い応答の提供が明示的に許可される場合もあります。その可否には、再利用を禁じる指定や切断状態など、別の規則が関わります。
反対に、年齢が52秒でfreshでも、それだけで再利用が確定するわけではありません。要求と保存済み応答が対応するか、Varyで分けられた条件が一致するか、no-cacheによる検証が必要か、といった点を確認します。鮮度の計算は、キャッシュ判断を構成する一段階です。
調査するときは、「60秒という設定を見た」だけで終わらず、どのキャッシュに適用される期間なのか、受信したAgeはいくつか、要求と応答の時刻をどう記録したか、受信後どれだけ保存したかを分けて残します。数値を同じ基準で比べることで、保存の効果と、古い内容を使い続ける時間の上限を読み違えにくくなります。
出典
- [1] RFC 9111: HTTP Caching(2022年6月) — 第4.2節の鮮度モデル、第4.2.1節の有効期間、第4.2.3節の年齢計算、第4.2.4節の古い応答の提供条件、第5.1節のAge。本文の秒数と図は、条件を明記した独自の計算例です。
