CloudflareがCache RulesでHTTP「Vary」ヘッダーの制御に対応
Cloudflareは2026年9月22日、HTTPのVaryヘッダーに基づくキャッシュ制御機能の提供を発表しました[1]。オリジンサーバーが返すVaryヘッダーに従い、リクエストヘッダーごとの処理をCache Rulesで制御できます[1]。この機能は発表当日より、Free、Pro、Business、Enterpriseの全プランで利用可能になりました[2]。これにより、すべてのプランの利用者がエッジでの高度なVary制御を活用できます[3]。
本機能では、オリジンサーバがVaryヘッダーを用いてレスポンスに影響し得るリクエストヘッダーを宣言します[4]。CloudflareのCache Rules側では、宣言された各ヘッダーに対するキャッシュの振る舞いを指定します[5]。利用者はヘッダーごとにnormalize、passthrough、bypassのいずれかを選択できます[6]。オリジンとエッジの役割を分離することで、柔軟なキャッシュ管理を実現できます[7]。
設定はCloudflareダッシュボードの「Caching」内にある「Cache Rules」から実施できます[8]。Rulesets APIのhttp_request_cache_settingsフェーズやTerraformからの設定にも対応しています[9]。インフラのコード化を進める組織でも、既存の構成管理にスムーズに統合できます。
後輩キャッシュの挙動はオリジンサーバーが決めるものだと思っていましたが、なぜCDN側で制御する必要があるんですか?
先輩オリジンはコンテンツが変わる条件を知っているけれど、エッジでどう束ねるのが配信効率として最適かまでは判断できないからだよ。
後輩オリジンの宣言を受け取った上で、CDN側でキャッシュのまとめ方を調整できるのが新しいわけですね。
先輩その通りだね。オリジンがVaryを返していれば、エッジ側のルールでヘッダーごとの扱いを設定できるのが大きな利点だよ。
HTTP「Vary」ヘッダーの役割とキャッシュ断片化の課題──なぜ今対応が必要なのか
HTTPのVaryレスポンスヘッダーは、オリジンが表現の選択で参照したリクエストの部分を示す標準機構です[10]。これはURIだけではレスポンス表現を選べない場合に、キャッシュが参照すべき要素を示します[11]。クライアントの環境に応じて異なる内容を返す、コンテントネゴシエーション(内容交渉)で用いられます。Varyにヘッダー名が列挙されると、キャッシュは同一URIでも値が一致する場合にのみ保存内容を再利用します[12]。
指定されたリクエストヘッダーはキャッシュキーの追加要素として扱われ、適合する要求だけが再利用されます[13]。キャッシュキーとは、保存されたデータを一意に識別するための検索識別子です。URIが同一でも指定ヘッダーが一致しないレスポンスは再利用されず、安全な分離が行われます[14]。Varyに複数のヘッダーがある場合、各値を組み合わせてバリアント(表現の差分)を判定します[15]。これにより、同一URLに対して言語や形式の異なる複数の表現を安全に保持できます。
キャッシュの期限切れに伴う再検証では、キャッシュは保存されたVary指定ヘッダーを複製します[16]。その上でオリジンに対して条件付きリクエストを生成します。オリジンから304(Not Modified)が返れば保存内容を更新して再利用し、完全な応答なら内容を置き換えます[16]。
同一URLから複数の表現を配信するサイトでは、Varyによる制御が必要です[17]。同一URLから言語、画像形式、圧縮方式、地域向けコンテンツを配信する構成があります。もしキャッシュがVaryを無視すると、先に保存された応答が別クライアントへ誤配信される危険があります[17]。エンドユーザーに正しい形式を届けるためにも、Varyの厳密な考慮が不可欠です[18]。
しかし、従来のVary実装には深刻な課題が存在していました。キャッシュはヘッダー値の表記差を、意味のあるレスポンス差と区別できませんでした[19]。たとえば大文字や小文字、空白、記述順序の違いだけで、同一内容のキャッシュが分散してしまいます[20]。このキャッシュ断片化は容量を無駄に消費し、エントリー同士の追い出し(退避)を招きます[21]。結果としてヒット率が著しく低下し、オリジンへのアクセス負荷を増やしてしまいます[22]。
さらに複数のVary対象を組み合わせると、バリアント数は値の組み合わせの積で急激に増加します[23]。たとえば各10値のヘッダーを3項目組み合わせると、それだけで1,000通りのバリアントが生じます[24]。1項目あたり10値を持つ3つのヘッダーで1,000通りに達する計算は、断片化の深刻さを示しています[25]。
Cloudflareの調査では、約5万サイトの1億2千万超のレスポンスを分析した結果が公表されています[26]。その結果、約3千サイトが4項目以上のヘッダーでレスポンスを変動させていました[27]。1億2,000万超のレスポンス分析は、多項目による変動が現実の課題であることを裏付けています[28]。組み合わせ爆発によってキャッシュが細分化されると、保存内容がほとんど再利用されない事態に陥ります。
後輩HTTP標準のVaryに従って厳密にキャッシュを分けるのは、本来とても安全なことですよね?
先輩安全ではあるけれど、文字の大小や空白の違いまで別物として扱うと、キャッシュが細切れになってしまうんだ。
後輩正確さを優先した結果としてキャッシュがほとんど再利用されず、オリジンへの負荷が増えてしまうのは皮肉ですね。
先輩そうなんだ。多言語化や最適化を進めるほどバリアントが増えて、キャッシュが効きにくくなるという矛盾を抱えていたんだよ。
3つのアクションと従来手法との違い──Cache RulesによるVary制御の仕組み
CloudflareのCache Rulesでは、オリジンが返したVaryヘッダーの各項目に3つの処理を指定できます[29]。指定できるアクションは、normalize、passthrough、bypassの3種類です。normalizeは同等と判断できるリクエストヘッダー値を同じキーへ集約し、キャッシュの共有を促進します[20]。意味的に同等な値を単一キーへまとめることで、キャッシュエントリー数を抑えてヒット率を改善できます[30]。同一内容に対するキャッシュエントリーの分散を防ぐため、normalizeの活用が推奨されています[31]。これにより、不要なキャッシュバージョンを削減しヒット率を高めることが可能です[32]。
passthroughはヘッダーの生の値をキャッシュ照合に使い、表記差を厳密に別バリアントとして扱います[33]。大小文字や空白、順序などの生値を使うため、表記差でも別バリアントとして保持されます[34]。オリジンがその差を意味のある差として扱う場合に適しています。ただし、オリジンが同等と扱う場合でも差を保持するため、断片化を温存する側面があります[35]。bypassはオリジンのVaryに指定された対象ヘッダーを含むレスポンスを保存せず、新規エントリーを作りません[36]。該当ヘッダーが現れたレスポンスを保存しないことで、個別バリアントの過剰な蓄積を遮断します[37]。
各アクションには明確な使い分けが存在します。normalizeは、Accept(形式)、Accept-Language(言語)、Accept-Encoding(圧縮方式)での利用を想定しています[38]。これらは有限の表現へ集約できるため、normalizeの適用が基本となります[39]。passthroughはヘッダー値の完全一致がレスポンス差分になる場合に適しています[38]。生値の違いが実際の応答差分を意味するAPIやコンテンツ配信に向いています[40]。bypassはCookieやUser-Agentのように値の種類が多い高カーディナリティな項目や個人単位の値に適しています[38]。高カーディナリティとは、値の種類が膨大に存在する状態を指します。個別ユーザー向けバリアントのキャッシュ保存を避け、安全性を優先する運用を可能にします[41]。CookieやUser-Agentなどの予測困難なヘッダーにbypassを設定することで、誤配信や断片化のリスクを抑制できます[42]。bypassを適用したレスポンスはキャッシュされないため、対象リクエストはオリジン処理へ委ねられます[43]。
オリジンへの転送処理にも重要な違いがあります。normalizeでは、キャッシュ照合とオリジンの表現選択を一致させるため、正規化後の値がオリジンへ転送されます[44]。AcceptとAccept-Languageについては、正規化後の値がオリジンへ送られます。Accept-Encodingについても、「Respect Strong ETags」が有効な場合は正規化後の値が転送されます[44]。正規化値をオリジンへ送ることで、オリジンが生成する表現とエッジの照合条件を一致させられます[45]。passthroughでは対象ヘッダーが変更されずにオリジンへそのまま転送されます[46]。
3つのアクションの挙動と推奨される適用先を比較すると、以下の表のようになります。
| アクション | キャッシュ生成の挙動 | オリジンへの転送処理 | 主な適応対象ヘッダー |
|---|---|---|---|
| normalize | 同等の値を集約し同一キーでキャッシュ[47] | 正規化後の値を転送(Accept, Accept-Language等)[44] | Accept, Accept-Language, Accept-Encoding[38] |
| passthrough | 生値の差異を厳密に別バリアント化[47] | 生ヘッダーを変更せず転送[46] | 完全一致がレスポンス差になる項目[38] |
| bypass | 該当ヘッダーを含む応答を保存しない[47] | オリジンへ転送し直接処理[36] | Cookie, User-Agentなど[41] |
オリジンレスポンスに対するCache Rulesの判定と各アクションへの分岐は、次のフローチャートのように実行されます。特に「Vary: *」ヘッダーが返された場合、リクエストヘッダー以外の情報が変動要因になり得ることを示します[48]。クライアントIPアドレスなどの外部要素が応答に影響する可能性があるためです。この場合、キャッシュは自力で適合性を判断できず、設定にかかわらず保存されません[49]。Vary: *による制約は今回のCache Rules新機能でも解消されず、常にバイパスされます[50]。標準仕様上もVary: *を含むレスポンスは一致判定に失敗し、キャッシュ保存されません[51]。外部情報が影響し得るため、オリジン問い合わせが必須となります[52]。このようにHTTP標準上もCloudflare上も再利用されません[53]。
今回のCache Rules対応は、従来の配信手法と比較して運用の柔軟性と効率性を大きく高めます。従来のCloudflare CDNはAccept-Encodingを上書きして再圧縮する方式でした[54]。一般的なVaryをオリジン起点で柔軟に扱う仕組みとは異なっていました。画像向けの既存機能もAcceptヘッダーに基づく画像形式のバリアントに限定された仕組みでした[55]。今回の対応は画像専用機能やコード記述に依存せず、多様なVary宣言に汎用的に対応できる点に意義があります[56]。
Workersのcf.varyはサブリクエスト単位の手段でしたが、今回はルールとしてノーコードで設定できます[57]。ダッシュボードやAPIからゾーン全体のルールとして適用できる点が大きな進歩です。また手動で設定するカスタムキャッシュキーは、全レスポンスに一律で次元を追加してしまいます[58]。そのため不要なキー分割やロジック重複を招く課題がありました。一律設定のカスタムキャッシュキーに対し、Varyはオリジンが返したヘッダーだけを対象にするため無駄がありません[59]。オリジンが実際に返したVaryに応じて次元を追加できるため、ロジックの重複を効果的に抑制できます[60]。
後輩以前からWorkersを使えば似たような制御はできたようですが、設定項目として組み込まれた意義は何ですか?
先輩コードを一行も書かずに、ダッシュボードやAPIのルール定義だけで安全に一元管理できる点だね。
後輩カスタムキャッシュキーのように、無関係なリクエストまで一律に分割して容量を圧迫する心配もありませんね。
先輩その通りだよ。オリジンが実際に返したヘッダーにだけ反応するから、無駄なキャッシュ分割を防げるのが合理的だね。
Webサイト運営者とエンドユーザーにもたらされる恩恵
Cache RulesによるVary制御の登場は、Webサイト運営者に対して大きな運用上の利点をもたらします。本機能はFreeを含むすべての料金プラン向けに提供されており、小規模なサイトでも即座に活用できます[2]。Workersコードを実装することなく、ダッシュボードやAPI、Terraformから容易に設定可能です[9]。全プランで提供されたことにより、Workersコードを書かずにCache Rulesから設定できます[4]。
多言語サイトや画像・JSON形式を出し分けるサービスでは、normalizeによってキャッシュ共有を拡大できます[61]。Accept-Languageで言語を集約したり、Acceptで形式を選択したりする構成において有効です。表記揺れによる無駄なバリアント生成が抑えられ、エッジでのキャッシュヒット率が向上します。ヒット率の改善により、条件によってはオリジンへの問い合わせや応答時間を減らせる可能性があります。
エンドユーザーにとっても、閲覧体験の信頼性が大幅に向上します。訪問者のブラウザが送信したAcceptやAccept-Languageに応じた正しい表現が、同一URLから確実に選択されます[18]。キャッシュの誤用によって意図しない言語が表示されたり、非対応の形式が返されたりする誤配信のリスクを抑えられます。適切に設定すれば、リクエストに応じた表現をキャッシュから再利用できる場合があります。
後輩この恩恵を大きく受けるのは、多言語サイトや複雑なAPIを大規模に運用している組織でしょうか?
先輩大規模サイトに限らず、単一のURLで画像形式や圧縮方式を出し分けている一般的なWebサイトでも効果があるよ。
後輩ユーザーにとっても、ブラウザに合わない形式が届いたり表示が乱れたりする事故が防げるのは安心ですね。
先輩全プランで開放されたから、無料枠で個人サイトを運営している人でも恩恵を受けられるのが素晴らしいところだね。
失敗を防ぐための設計指針と運用上の注意点
新機能を安全に活用するためには、オリジンサーバー側の設計が一貫している必要があります。オリジンは、リクエストヘッダーによって差分が生じるすべてのキャッシュ可能レスポンスでVaryを一貫して返す必要があります[62]。エラー応答やフォールバック応答も含めて徹底しなければなりません。エラーやフォールバック応答でVaryが欠落すると、分離すべきレスポンスが誤って共通キャッシュとして保存される危険があります[63]。その結果、後続のリクエストに誤ったコンテンツが配信されてしまいます。
高カーディナリティなヘッダーの取り扱いには細心の注意を払う必要があります。CookieやUser-Agentなどの高カーディナリティなヘッダーをVary対象として保存する設計は避け、bypassまたはCache-Control: privateを優先すべきです[64]。個人単位のトークンなども含め、これらを共有キャッシュに保存すると断片化やユーザー間の誤配信につながるおそれがあります。実務上は、Cache Rulesのデフォルト動作(default)をbypassに設定し、安全なヘッダーのみを個別に許可する構成が有効です[65]。予期しないVaryヘッダーによるキャッシュ肥大化を確実に防げます。
normalizeの適用に際しても、事前の十分な検証が求められます。normalizeは小文字化や品質値による並べ替え、言語タグの短縮を行うため、設定とオリジンの解釈が一致しているか注意が必要です[66]。言語タグ短縮の過程で、受け入れ拒否を示すq=0が脱落するケースもあります。同じ正規化キーに入る要求群が常に同一の表現を返すかを、実装仕様と実測レスポンスの両面から検証して安全性を判断すべきです[67]。
運用管理上の注意点として、Vary設定の変更は既存キャッシュを自動削除しません[68]。そのため、新キーへの再充填や古いエントリーの残存に注意を払う必要があります。設定変更後は旧キーの残存や継続的なMISS、想定外のBYPASSが発生していないかを監視する必要があります[69]。なお、URLをパージすると紐づくすべてのVaryバリアントが一括で削除されるため、バリアントごとの個別パージは不要です[70]。キャッシュクリアの運用負荷を抑えられる設計になっています。
本番投入前後は、同一URLに対して異なるヘッダー値や欠落、q=0、フォールバック応答を送信するテストが妥当です[71]。レスポンス本文やヘッダー情報とCF-Cache-Statusを突き合わせることで、意図通りのバリアント分離を確実に検証できます[71]。段階的なテストを経ることで、キャッシュの断片化や誤配信を防ぎながら安定した運用を実現できます。
後輩CDN側のルールを整えれば、オリジン側の設定はこれまで通りでも問題ないんでしょうか?
先輩そこが落とし穴で、オリジンがエラー時やフォールバック時にVaryを返し忘れると、誤ったキャッシュが残ってしまうよ。
後輩設定を変更しても古いキャッシュが自動で消滅しないなら、事前の切り替え手順や監視の設計も必須になりますね。
先輩正規化によって意図しない形式が返されないかも含めて、本番導入前に実リクエストで突き合わせることが大切だよ。



