【実務・中級編】Last-ModifiedとIf-Modified-Sinceによる時刻ベースのキャッシュ制御 – HTTPプロトコル・通信規格実践ガイド

キャッシュ制御の古典にして至宝:Last-ModifiedとIf-Modified-Sinceの「現場的」流儀

ネットワークエンジニアとして数多のトラフィックを見てきましたが、現代のWeb API設計やインフラ最適化においても、結局のところ最後に行き着くのは「HTTPの基本」です。

今日は、HTTP/1.0から脈々と受け継がれるキャッシュ検証の基本メカニズム、`Last-Modified`と`If-Modified-Since`について深掘りします。「今さら?」と思うなかれ。この古風な仕組みを正しく理解し、ETagとの関係性を整理できているか否かが、あなたのシステムのレスポンスタイムと、サーバーの負荷耐性を左右するのです。

—

1. なぜ「時刻」でキャッシュを検証するのか

HTTP通信において、クライアントが手元のキャッシュを再利用して良いかを確認するプロセスを「条件付きリクエスト(Conditional Request)」と呼びます。

その最もシンプルな形態が、サーバー上の最終更新日時(Last-Modified)を基準にする方法です。

通信フローのリアル

1. 初回リクエスト: クライアントがGET。サーバーはレスポンスに `Last-Modified: Wed, 21 Oct 2023 07:28:00 GMT` を付与。
2. キャッシュ保持: クライアントはこの時刻をローカルに保存。
3. 2回目以降: クライアントは `If-Modified-Since: Wed, 21 Oct 2023 07:28:00 GMT` をヘッダーに載せて問い合わせる。
4. サーバー判定:

  • 変更なし:サーバーは `304 Not Modified` を返す。ボディは空。帯域の節約!
  • 変更あり:サーバーは新しいリソースと共に `200 OK` を返す。

この「304」が返る時、ネットワークを流れるパケット量は最小限に抑えられます。これがインフラエンジニアにとっての正義です。

—

2. 時刻ベース制御の「限界」とETagという相棒

実務で必ず直面するのが「時刻の精度」問題です。

  • 解像度の問題: HTTPの時刻フォーマット(RFC 7231)は秒単位です。1秒間に何度も更新されるような動的なリソースでは、正確な判定ができません。
  • 物理的なズレ: サーバーが複数台ある場合、各ノードのシステム時刻が完全に同期していないと、キャッシュの不整合が発生します。

ここで登場するのが ETag(Entity Tag) です。これはリソースの内容をハッシュ化した指紋のようなもの。RFC 7232でも、「ETagが優先される」と明記されています。もしETagとIf-Modified-Sinceが両方送られてきた場合、サーバーは通常ETagによる検証を優先します。

—

3. 実践:デバッグと実装の現場から

まずは `curl` を使って、この挙動を自分の目で確かめてみましょう。

1. まずリクエストを送って Last-Modified を確認する
curl -I https://example.com/api/data

2. 取得した日時を指定して条件付きリクエストを送る
curl -I -H “If-Modified-Since: Wed, 21 Oct 2023 07:28:00 GMT” https://example.com/api/data
成功すれば “HTTP/1.1 304 Not Modified” が返ってくるはずです

Python (Requests) でのキャッシュ制御例

APIクライアントを開発する際、requestsライブラリでこれを制御するなら以下のようになります。

import requests
from datetime import datetime

以前取得した最終更新日時
last_modified = “Wed, 21 Oct 2023 07:28:00 GMT”

headers = {
“If-Modified-Since”: last_modified
}

response = requests.get(“https://example.com/api/data”, headers=headers)

if response.status_code == 304:
print(“キャッシュが有効です。ローカルのデータを使います。”)
elif response.status_code == 200:
print(“リソースが更新されました。データを同期します。”)

Nginxでの設定Tips

サーバー側で静的ファイルを配信する場合、Nginxは自動的に `Last-Modified` を付与してくれますが、設定で調整することも可能です。

location /static/ {
# 静的ファイルのキャッシュ制御
expires 1d;
add_header Cache-Control “public, must-revalidate”;
# ここでETagを有効にしておくと、時刻ベースより強力なキャッシュ制御が可能
etag on;
}

—

4. エンジニアへのアドバイス:トラブルシューティングの勘所

現場でよくあるトラブルは「キャッシュが更新されない」という相談です。そんな時はまず以下の3点を確認してください。

1. 時刻のフォーマット: `If-Modified-Since` は必ず RFC 1123 形式(例: `Wed, 21 Oct 2023 07:28:00 GMT`)である必要があります。自作のAPIでここを誤ると、サーバーは無条件で `200 OK` を返してしまい、キャッシュが効きません。
2. プロキシの介入: CDNや中間プロキシが `If-Modified-Since` を削除していないか? `Vary` ヘッダーの設定が適切かを確認してください。
3. 時刻の不一致: サーバーが分散している環境では、`Last-Modified` ではなく、ETag(ファイルの内容ハッシュ値)の使用を強く推奨します。時刻に頼る運用は、いつか必ず物理的な時刻同期の罠に足元をすくわれます。

HTTPの仕様は枯れていますが、それゆえに最強のツールです。最新のフレームワークやライブラリの裏側で、パケットがどのような「会話」をしているのか。その想像力を働かせることが、一流のエンジニアへの近道です。

さあ、今日もプロトコルと対話しましょう。何か不明点があれば、またいつでも聞いてください。

コメント

タイトルとURLをコピーしました