【実務・中級編】If-Modified-Sinceヘッダーによる条件付きGETリクエスト – HTTPプロトコル・通信規格実践ガイド

帯域を無駄にするな:If-Modified-Sinceで実現する「賢い」キャッシュ戦略

Webインフラの現場にいると、時折「なぜかレスポンスが重い」「帯域が逼迫している」という相談を受ける。原因を探ると、クライアントが毎回律儀に巨大なデータを全件取得し、サーバーが律儀にそれを全送信している……なんていう非効率な光景に出くわすことが多い。

HTTP/1.1の時代から続く「条件付きGET(Conditional GET)」という概念は、一見地味だが、Webアプリケーションのパフォーマンスとコスト効率を左右する極めて強力な武器だ。今回は、その主役である `If-Modified-Since` ヘッダーについて、現場の視点から深掘りしてみよう。

なぜ「全件取得」が罪なのか

HTTP/0.9からHTTP/1.1への進化の歴史は、いかに効率よくデータを運ぶかという戦いだった。サーバー上のリソースが変わっていないのに、クライアントが毎回「そのファイルをくれ」と言い、サーバーが「はい、どうぞ」とバイト列をすべて送り直す。これは、昨今のクラウドの転送量課金を考慮すれば、ただの「金ドブ」に等しい。

ここで登場するのが If-Modified-Since だ。

クライアントは「このファイル、〇〇年〇月〇日より後に更新されてる?」とサーバーに尋ねる。サーバーは最終更新日(Last-Modified)を確認し、変更がなければ「304 Not Modified」という、ボディを含まない軽量な応答を返すだけでいい。これが、帯域節約の要諦だ。

通信フロー:304応答の舞台裏

この仕組みは、初回アクセスと2回目以降のアクセスで役割分担が明確に分かれている。

1. 初回アクセス:サーバーは `Last-Modified: Wed, 21 Oct 2023 07:28:00 GMT` といった日付を付与してリソースを送る。クライアントはこの日時をブラウザキャッシュやローカルストレージに保存する。
2. 2回目以降:クライアントはリクエストヘッダーに `If-Modified-Since: Wed, 21 Oct 2023 07:28:00 GMT` を付与して送る。
3. 判定:サーバーはリソースの現在の更新日時と、ヘッダーの日時を比較する。

  • 更新なし:`304 Not Modified` を返す。ボディは空。
  • 更新あり:`200 OK` を返し、新しいボディと新しい `Last-Modified` を送る。

実践:curlとブラウザでの確認

理屈はわかっても、手を動かさなければエンジニアとは言えない。まずは `curl` で挙動をトレースしてみよう。

初回取得(Last-Modifiedを確認)
curl -I https://example.com/api/data.json

2回目:If-Modified-Sinceを付与して確認
curl -I -H “If-Modified-Since: Wed, 21 Oct 2023 07:28:00 GMT” https://example.com/api/data.json

もしサーバーが正しく実装されていれば、2回目のレスポンスステータスは `304` になるはずだ。

また、フロントエンド開発でFetch APIを使う場合も、ブラウザは自動的にこのヘッダーを管理してくれるが、キャッシュをバイパスしたい場合は `cache: ‘no-cache’` を指定するなどの制御も重要になる。

// Fetch APIでのリクエスト例
fetch(‘https://example.com/api/data.json’, {
method: ‘GET’,
headers: {
// ブラウザのキャッシュ制御を明示する場合のヒント
‘Cache-Control’: ‘no-cache’
}
})
.then(response => {
if (response.status === 304) {
console.log(‘キャッシュが有効です。帯域を節約しました!’);
} else {
return response.json();
}
});

現場でハマりやすい「落とし穴」

この仕組み、一見完璧だが、運用でいくつか注意すべき点がある。

  • 時刻の精度:`Last-Modified` はHTTP日時のフォーマット(RFC 7231)に厳密に従う必要がある。サーバー側の時刻がずれていると、意図せずキャッシュがパージされたり、逆に古いデータが残り続けたりする。
  • 動的生成コンテンツ:PHPやNode.js等で動的に生成するAPIの場合、サーバー側で明示的に `Last-Modified` ヘッダーを出力し、かつ `If-Modified-Since` を判定するロジックを書かなければ、304は返らない。「何もしなくてもブラウザがキャッシュしてくれる」というのは間違いだ。
  • ETagとの併用:実は `If-Modified-Since` より `ETag` (ハッシュ値による比較) の方が、時刻のズレに左右されないため、現代的なWeb APIでは併用が推奨される。`If-None-Match` ヘッダーと `ETag` の組み合わせも、必ずセットで押さえておくこと。

締めくくり:インフラエンジニアの矜持

「動けばいい」というコードと、「どう通信が行われ、どうリソースを節約するか」を理解したコードの間には、雲泥の差がある。

HTTPヘッダーの小さな一行は、世界中のユーザーにとっての待ち時間の短縮であり、貴社のインフラコストの削減に直結する。今度、ブラウザのデベロッパーツールを開いたときは、ぜひNetworkタブを覗いてみてほしい。304の山を築けているなら、君の設計は正しい。

もし、すべてのレスポンスが200で返されているなら……今日から改善の余地があるということだ。ネットワークは、細部にこそ神が宿る。

コメント

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