Vary には、サーバーが公開ページの表現を選択する際に使うリクエストヘッダー名を設定します。Mac では、一度に 1 つのヘッダーをテストし、返されたドキュメントとメタデータを比較して、設定を変更する前にデフォルトのレスポンスを確認します。
このガイドは、公開ドキュメントを管理し、Mac のターミナルからその配信を確認する人を対象としています。例では、合成的な「Shape Guide」を、1 つの URL で HTML またはプレーンテキストとして提供します。実際に選択に使われる入力を特定し、対応するレスポンスヘッダーを設定して、その結果を検証します。
ページの Vary ヘッダーには何を含めるべきですか?
Vary は、リクエストメソッドと対象 URL 以外に、表現の選択に影響する可能性があるリクエストフィールドを示します。値には、要求されたメディアタイプではなく、Accept のようなヘッダー名を指定します。これは選択の動作を記述するものであり、追加しただけでその動作が実装されるわけではありません。RFC 9110: HTTP Semantics, section 12.5.5。
たとえば、サーバーが Accept を使って HTML とプレーンテキストのどちらかを選択するなら、該当するレスポンスフィールドは Vary: Accept です。配信レイヤーが Accept-Encoding を使って圧縮版と非圧縮版も選択するなら、その要素も含めます。Vary: Accept, Accept-Encoding。これは条件付きの例であり、すべてのページに共通する設定ではありません。Content negotiation。
実際に考えるべき問いは、「このヘッダーが変わることで、あるリクエスト向けに選択されたキャッシュ済みレスポンスが別のリクエストには適さなくなる可能性があるか」です。HTTP キャッシュでは、再検証せずに再利用する前に、指定されたフィールドが一致している必要があります。指定フィールドがない場合は、別のリクエストにもそのフィールドがない場合に一致し、フィールドが存在する場合には一致しません。RFC 9111: HTTP Caching, section 4.1。
まず、選択条件の一覧を作成します。アプリケーションのドキュメント選択ルールと、その後に適用されるレスポンス変換を確認してください。結果に違いがあれば有用な証拠ですが、2 つのリクエストで結果が変わらなかったからといって、サポート対象のすべての値についてそのヘッダーが無関係だとは言えません。
編集前にリクエストマトリクスを作る
合成的な Shape Guide では、HTML の希望があれば HTML、プレーンテキストの希望があればプレーンテキストを返し、Accept がない場合は HTML を返すものとします。どちらのバージョンにも「円、四角形、三角形」という同じ中立的な情報が含まれています。これは説明用の要件であり、公開サイトを観察した結果ではありません。
| テスト | リクエスト設定 | 想定される結果 | 確認する内容 |
|---|---|---|---|
| HTML | Accept: text/html |
HTML ドキュメント | 本文、Content-Type、Vary |
| プレーンテキスト | Accept: text/plain |
プレーンテキストのドキュメント | 本文、Content-Type、Vary |
| デフォルト | Accept フィールドなし |
HTML ドキュメント | デフォルトの選択と Vary |
| 繰り返し | プレーンテキストの後に HTML | 再び HTML ドキュメント | 先のバリアントが配信に影響するか |
| 未使用の入力 | 選択ルールにないヘッダーを変更 | 同じ表現が選択される | そのヘッダーを調査する必要があるか |
最初の比較では圧縮の条件を一定に保ちます。そうしないと、バイト列の違いがドキュメントではなく圧縮による可能性があります。まず形式の選択を調べ、その後に圧縮を別途確認してください。この区別は、Accept と Accept-Encoding の役割が異なることに基づいています。Content negotiation。
ファイルサイズだけに頼らず、意味のある違いを記録してください。この例では、プレーンテキストのレスポンスには HTML マークアップなしで図形名が含まれ、そのメディアタイプもプレーンテキストを示す必要があります。生成されるタイムスタンプが変わる場合は、すべてのバイト列の違いを新たなバリアントとみなす前に調査が必要です。
このマトリクスは診断用の補助であり、ネゴシエーションのテスト一式を網羅するものではありません。基本ケースが動作したら、ページがサポートする実際の複合的な希望や品質値を追加してください。単一のタイプを指定する簡単なリクエストでは、選択アルゴリズムのすべての分岐を試せません。
Mac のターミナルで比較可能なレスポンスを取得する
合成データを含む公開テストドキュメント、その最終的な HTTPS URL、および bash と curl が利用可能な Mac が必要です。この例では、テストドキュメントが前述の HTML/プレーンテキストの動作にすでに対応しているものとします。このドキュメントの作成、アップロード、公開は行いません。
Terminal を開き、以下のブロック全体を貼り付けます。プロンプトが表示されたら、合成ドキュメントの URL を入力してください。スクリプトは新しい一時レポートディレクトリを作成し、各レスポンスの本文をヘッダーとともに保存します。以前のレポートは上書きしません。
bash <<'BASH'
set -eu
printf 'Public synthetic page URL: ' > /dev/tty
IFS= read -r page_url < /dev/tty
case "$page_url" in
https://*) ;;
*) printf 'Enter an HTTPS URL.\n' >&2; exit 1 ;;
esac
report_dir=$(mktemp -d "${TMPDIR:-/tmp}/vary-check.XXXXXX")
printf 'Report directory: %s\n' "$report_dir"
for sample in html plain absent html-again; do
case "$sample" in
html|html-again) accept_header='Accept: text/html' ;;
plain) accept_header='Accept: text/plain' ;;
absent) accept_header='Accept:' ;;
esac
curl --disable --silent --show-error --fail \
--connect-timeout 5 --max-time 20 \
--header "$accept_header" \
--header 'Accept-Encoding: identity' \
--dump-header "$report_dir/$sample.headers" \
--output "$report_dir/$sample.body" \
--url "$page_url"
done
printf 'Finished. Responses saved in: %s\n' "$report_dir"
BASH
ここでは、--header で制御対象のリクエストフィールドを指定し、Accept: で curl が内部生成する Accept フィールドを削除します。--dump-header と --output は、ヘッダーと本文を別々に保存します。接続時間と転送時間の上限により、各リクエストの所要時間を制限します。これらのオプションは curl manual に記載されています。
curl が転送エラー、または --fail の対象となる HTTP エラーを報告すると、スクリプトは停止します。再試行する前に、報告されたディレクトリを確認してください。以前のキャプチャが残っている場合があり、転送に失敗するとファイルが不完全なことがあります。意図的にリダイレクトを追跡しないため、各ヘッダーファイルのステータス行を確認してください。リダイレクトをキャプチャした場合は、最終ドキュメントの URL を使って新しいレポートを開始します。curl manual。
スクリプトが表示したパスを使って、Finder でレポートディレクトリを開きます。ファイルをプレーンテキストエディターで確認してください。html.body と plain.body を比較し、次に html.body と html-again.body を比較します。absent.headers も、明示的な希望を指定したレスポンスと同じように注意して確認してください。
保存した結果は、このリクエスト順序で得られた観察結果として扱ってください。共有キャッシュが何かを保存した証明にはなりません。キャッシュの再利用を試す必要がある場合は、文書化されたキャッシュ可能な条件の下で、想定する配信経路を通してシーケンスを繰り返し、プレーンテキストを先にする順序でも試してください。
レスポンスを生成するレイヤーで結果を適用する
説明用の Shape Guide では、形式選択の証拠から Accept が選択フィールドであると判断できるはずです。HTTP レスポンスを生成または確定する場所で設定してください。別のレイヤーが必要な Vary の値をすでに追加している場合は、形式選択の値を追加する際にそれを保持します。最終的なリストには、選択動作全体が記述されている必要があります。RFC 9110: HTTP Semantics。
以下は、形式選択と圧縮ネゴシエーションの両方が有効な場合の、例示用レスポンスヘッダー断片です。HTTP レスポンス全体でもサーバー設定ファイルでもありません。
Vary: Accept, Accept-Encoding
ネゴシエーションされたバリアントとデフォルトのレスポンスには、同じ意図した Vary リストを使い、該当する 304 Not Modified レスポンスでもそのリストを保持します。MDN はこの一貫性要件を明示しています。最初に成功した HTML レスポンスだけでなく、これらのレスポンス経路も検証対象にしてください。Vary header。
meta 要素に http-equiv="Vary" を追加しても、サポートされる代替手段にはなりません。WHATWG は、Vary を含まない特定の HTML プラグマディレクティブを定義し、それらのディレクティブは HTTP ヘッダーとはほぼ別個のものだと説明しています。実際のレスポンスヘッダー設定を使用してください。HTML Standard: Pragma directives。
公開インターフェースでレスポンスヘッダーを設定できない場合は、ホスティング層やアプリケーション層に、文書化された対応があるか確認してください。それが利用できない場合、この合成例では、1 つの URL で形式をネゴシエーションする代わりに、HTML とプレーンテキストのドキュメントに安定した表現を持つ別々の URL を割り当てる方法があります。これにより、その選択要素はなくなりますが、他の変換については引き続き個別の評価が必要です。
バリエーションの欠落、過剰、誤解を招く設定を診断する
キャプチャを使って、次に何を調べるか決めます。以下の判断材料は、例に記載された動作を対象とするものであり、特定のホスティングサービスについての主張ではありません。
| 観察結果 | 次に調べること |
|---|---|
HTML リクエストとプレーンテキストのリクエストで形式が異なるが、Vary に Accept がない |
最終レスポンスヘッダーの組み立て箇所を確認する |
明示的なバリアントには Accept が含まれるが、デフォルトのレスポンスにはない |
フォールバックのレスポンス経路を確認する |
| HTML リクエストの繰り返しでプレーンテキスト版が返る | オリジンでの選択とキャッシュ経由の配信を比較する |
| すべてのリクエストで同じ HTML ドキュメントが返る | 形式に関する値を追加する前に、形式ネゴシエーションが存在するか確認する |
無関係なヘッダーが Vary に含まれる |
削除する前に、それを必要とする選択ルールを特定する |
| ブラウザーのサイズ変更でレイアウトが変わるが、配信される HTML は変わらない | これがサーバー側の選択ではなく、レスポンシブな表示かどうか確認する |
デフォルトのレスポンスに関するケースは特に注意が必要です。RFC 9111 は、デフォルトのレスポンスで Vary を省略すると、他の選択肢があるにもかかわらず、そのレスポンスが後続リクエストに選ばれる場合があると説明しています。明示的なバリアントとあわせて、デフォルト経路も修正してください。RFC 9111: HTTP Caching。
未完成の調査一覧を埋める近道として Vary: * を使わないでください。HTTP キャッシュのルールでは、この値を含む保存済みレスポンスは常に一致判定に失敗します。ドキュメントを選択するリクエストフィールドも特定できません。RFC 9111: HTTP Caching。
ターミナルでの比較後にブラウザーで確認することも有用です。WHATWG の Fetch Standard は、HTTP キャッシュのレスポンスを選択する際に Vary を明示的に考慮します。制御された curl リクエストだけでなく、通常のブラウザー読み込み経路でもドキュメントを確認してください。Fetch Standard: HTTP-network-or-cache fetch。
ページ配信と Google 検索の要件を整合させる
デバイスに応じてページを変える場合は、レスポンシブデザインと動的配信を区別します。Google によると、レスポンシブデザインではデバイスにかかわらず同じ URL で同じ HTML を提供します。一方、動的配信では User-Agent を使って異なる HTML を選択し、Vary: User-Agent を使用します。Google は、実装と保守が容易なレスポンシブデザインを推奨しています。Mobile site and mobile-first indexing best practices。
したがって、CSS で同じ HTML のレイアウトを変えるだけの合成的な Shape Guide では、そのレイアウト変更だけを理由に User-Agent で変化させる必要はありません。サーバーがデバイスに応じて実際に異なる HTML を選択する場合は、そのデバイスのケースをリクエストマトリクスに追加してください。Google は、デスクトップ版とモバイル版で主要なコンテンツを同等に保つことも推奨しています。Mobile site and mobile-first indexing best practices。
最後に、確認しやすい小さな配信記録をまとめます。ドキュメントの選択ルール、リクエストマトリクス、取得したレスポンス、そして最終的な Vary リストを含めてください。リスト内の各ヘッダーには明確な役割があり、サポート対象の各バリアントを引き続き識別でき、デフォルトのレスポンスも同じ配信契約に従う必要があります。
出典
- RFC 9110: HTTP Semantics — IETF / RFC Editor。
- RFC 9111: HTTP Caching — IETF / RFC Editor。
- Fetch Standard — WHATWG。
- HTML Standard — WHATWG。
- curl — How To Use — curl project。
- Vary header — MDN Web Docs。
- Content negotiation — MDN Web Docs。
- Mobile site and mobile-first indexing best practices — Google Search Central。