「キャッシュの罠」を回避せよ:HTTP/1.1 `Vary` ヘッダーが握るWeb高速化の鍵
インフラエンジニアとして現場に立っていると、時折「なぜか一部のユーザーに古いコンテンツが表示される」「PC版のキャッシュがスマホ版に誤配信された」といった、不可解な挙動に遭遇することがある。
その原因の多くは、HTTP/1.1の仕様において非常に重要でありながら、見落とされがちな `Vary` ヘッダーの不適切な設定にある。今日は、キャッシュサーバーを正しく操り、Web APIの信頼性を担保するための「Varyヘッダーの深層」を、実務的な視点で解説していこう。
—
1. なぜ `Vary` が必要なのか?
HTTPキャッシュは、オリジンサーバーの負荷を下げ、ユーザーへのレスポンスを爆速化するための強力な武器だ。しかし、Webの世界には「同じURLでも、リクエストヘッダーに応じて中身を変えたい」という要件が山ほどある。
例えば、以下のようなケースだ。
- Accept-Encoding: ブラウザがGzipやBrotliに対応しているか。
- User-Agent: スマホ用とPC用でページを出し分けたい(現代ではレスポンシブが主流だが、レガシーな環境ではまだ現役だ)。
- Authorization: 認証トークンごとに個別のレスポンスを返したい。
ここで、もしキャッシュサーバーが単に「URL」だけを見てレスポンスを返すとどうなるか。スマホユーザーがPC用のキャッシュを掴まされ、サイトのレイアウトが崩壊するという惨劇が起きる。
`Vary` ヘッダーは、キャッシュサーバーに対し「このレスポンスは、リクエストヘッダーの『これ』と『あれ』の値が一致した時だけ有効だよ」と明示する、いわば「キャッシュの属性定義書」なのだ。
—
2. 通信フローで見る `Vary` の役割
キャッシュのヒット・ミスは、以下のようなシーケンスで決定される。
1. Client → Cache Server: `GET /api/data` をリクエスト。
2. Cache Server: キャッシュを確認。ヒットしなければ Origin Server へ転送。
3. Origin Server: 処理を行い、レスポンスを返す。この時、`Vary: Accept-Encoding, Authorization` を付与。
4. Cache Server: この `Vary` を見て、「おっ、今後このURLのキャッシュを返す時は、リクエストの `Accept-Encoding` と `Authorization` が完全に一致するか確認しなきゃいけないな」と記憶する。
もし `Vary` が適切に設定されていないと、最初にキャッシュされたパケットが、異なる条件のリクエストに対しても「使い回される」というキャッシュ汚染(Cache Poisoning)が発生する。
—
3. 実践:Varyの正しい設定とデバッグ
設定例:Nginxでの記述
NginxでAPIサーバーをリバースプロキシとして運用する場合、レスポンスヘッダーに忘れずに含める必要がある。
location /api/ {
# レスポンスにVaryヘッダーを付与する
# 認証トークンと圧縮形式が異なる場合にキャッシュを分ける
add_header Vary “Authorization, Accept-Encoding” always;
proxy_pass http://backend_server;
}
デバッグ:curlで挙動を確認する
実際に自分のAPIが正しく `Vary` を返しているか、curlでサクッと確認するのが一番早い。
ヘッダー情報を取得して確認
curl -I -H “Accept-Encoding: gzip” https://api.example.com/data
出力結果の中に `Vary: Accept-Encoding` が含まれているかを確認しよう。もしこれが抜けている状態でキャッシュサーバー(CloudFrontやFastlyなど)を通すと、無差別なキャッシュ配布が始まる。
—
4. 注意すべき「Varyの落とし穴」
多くのエンジニアが陥る罠として、「ワイルドカードの乱用」がある。
`Vary: ` という設定を見たことはないだろうか? これは「あらゆるリクエストヘッダーが異なればキャッシュを分ける」という意味になる。理論上は安全だが、実務上はキャッシュヒット率がほぼ0%になるという致命的なデメリットを抱える。キャッシュサーバーは「何が来ても別物だ」と判断し、キャッシュを捨ててオリジンへ問い合わせ続けるからだ。
また、`User-Agent` を `Vary` に含めるのは、現代のWeb開発では避けるべきだ。User-Agentは非常に多様であり、キャッシュ効率が劇的に低下する。デバイス判定は、サーバー側ではなくクライアント側(CSSメディアクエリなど)で行うのが、モダンインフラの鉄則である。
—
最後に:ネットワークアーキテクトからの助言
`Vary` ヘッダーは、言わばキャッシュサーバーとの「契約」だ。ここを曖昧にすると、障害が発生した際にログをいくら追いかけても原因が掴めない、極めて難易度の高いバグを生むことになる。
- CDNやプロキシを使っているなら、まず `Vary` を疑え。
- キャッシュヒット率が異常に低いなら、`Vary` に不要なヘッダーが含まれていないか確認せよ。
ネットワークのトラブルシューティングにおいて、最後に行き着くのは「仕様の正確な理解」と「境界条件の確認」だ。今日の知識が、あなたのシステムの信頼性をさらに一段高める一助となれば幸いだ。
コメント