プロンプトと適用範囲
クライアントが透過的コンテントネゴシエーションを使用してリソースを要求し、HTTP 506 Variant Also Negotiates を受信します。システムには Apache スタイルのネゴシエーション、リバースプロキシ、およびキャッシュが存在します。セマンティクス、ループのトリガー、診断、キャッシュの挙動、およびフォールバックについて説明してください。
面接官が評価するポイント
- 506 が RFC 2295 の透過的コンテントネゴシエーションに由来することを理解しているか。
- ネゴシエーションループを 406 Not Acceptable やプロキシの 502 と区別できるか。
- Alternates、Variant-Vary、TCN、および関連メタデータを調査できるか。
- リトライ、キャッシュ、ダウングレードの境界を定義できるか。
- 循環検出、オブザーバビリティ、リリースゲートを追加できるか。
最初に確認すべき明確化事項
Accept と Accept-Language、リソースがバリアントリストであるか、どのレイヤーが 506 を発行しているか、プロキシキャッシュが関与しているか、固定の表現(representation)で許容されるかを確認します。バリアントがネゴシエーション中のリソースを指し戻している状況を前提とします。
30秒の回答フレームワーク
506 は透過的ネゴシエーションがループを形成し、サーバーが最終的な表現を選択できないことを意味します。単なるアップストリームの汎用的な障害として扱うのではなく、レスポンスチェーンとネゴシエーションメタデータをトレースして循環を証明します。クライアントは同じ構成でむやみにリトライすべきではなく、固定の表現を要求するかネゴシエーションを無効化できます。ネゴシエーションの深さを制限し、バリアントを修復し、406 に対する 506 の発生を監視します。
ステップごとの詳細解説
1. 透過的ネゴシエーションの説明
RFC 2295 では、オリジンがバリアントを公開し、クライアントや中間ノードがリクエストヘッダーから表現を選択できるようにします。リクエストは最終的に具体的なリソースへ収束しなければなりません。
2. ループの特定
バリアントが透過的ネゴシエーションを必要とする別のリソースを指している場合、選択処理が元のオブジェクトに戻る可能性があります。リソース URI、バリアント URI、ネゴシエーションプロキシ、リクエスト ID、および訪問済みセット(visited set)を記録します。ノードを再訪することは循環の証明になります。
3. 近接するステータスコードの識別
406 はクライアントの条件を満たす表現が存在しないことを意味します。502 はゲートウェイが無効なアップストリームレスポンスを受信したことを意味します。506 の調査では、最終的なエッジのステータスだけでなく、ネゴシエーションのグラフを追跡する必要があります。
4. クライアントフォールバックの設計
同一のヘッダーおよび構成でリトライしても循環は解消されません。固定バリアントを要求するか、透過的ネゴシエーションを省略するか、修復メッセージを表示します。構成変更後または明示的な一時的シグナルがある場合のみ、制限枠(budget)の範囲内でリトライします。
5. キャッシュキーと Vary の処理
キャッシュキーには、ネゴシエーションで使用される Vary ディメンションを含める必要があります。506 があらゆる表現に対する長期のレスポンスとしてキャッシュされてはなりません。エラーキャッシングについては Cache-Control に従い、修復後は古いプロキシエントリを考慮します。
6. サーバーの修復と保護
リリース前にバリアントグラフを構築し、深さと時間制限を設けた循環検出を実行します。内部の URI トポロジーではなく相関 ID(correlation id)を返します。プロキシは元のステータス、Via、トレースデータを保持し、リライトによって原因が隠蔽されないようにします。
7. 検証とオブザーバビリティ
自己循環、2ノード循環、深い非循環リスト、異なる Accept および言語ヘッダー、プロキシキャッシュ、ロールアウト、ロールバックをテストします。506/406、ネゴシエーション時間、フォールバック、キャッシュヒット、および修復時間を監視します。
質の高い模範回答
506 は RFC 2295 における透過的ネゴシエーションのループエラーです。バリアントがネゴシエーション対象のリソースを指し戻すと、サーバーは最終的な表現を生成できなくなります。私なら URI、バリアント、プロキシ、リクエスト ID を記録し、訪問済みセットを用いて循環を証明し、各ホップで元のステータスとトレースを保持します。
同一条件であればリトライせず迅速に失敗(fail-fast)させるべきです。クライアントは固定バリアントを要求できます。リリース前にサーバー側でバリアントグラフを構築し、循環をチェックし、深さと時間を制限して、Vary とキャッシュキーを検証します。受け入れ検証では、ヘッダーと言語の変更、プロキシキャッシュ、ロールアウト、ロールバック、および 406 との区別をカバーします。
よくある間違い
- 506 を 406 や 502 として扱うこと。
- バリアントグラフではなく、プロキシの最終ステータスのみを調査すること。
- 同一のネゴシエーション構成で無限にリトライすること。
- キャッシュキーから Vary ディメンションを除外すること。
- 循環検出や深さ制限を設けずにリリースすること。
- エラー内に内部バリアント URI を返してしまうこと。
フォローアップ質問と回答
フォローアップ 1: 506 と 406 の決定的な違いは何ですか?
406 は受け入れ可能な表現が存在しないことを指します。506 はネゴシエーションプロセス自体が循環し、収束できないことを意味します。
フォローアップ 2: クライアントは 506 をリトライできますか?
変更のない構成ではできません。修復後、または明示的な一時的シグナルを受信した場合のみ、上限回数(budget)内でリトライします。
フォローアップ 3: プロキシがステータスを変更したことをどのように証明しますか?
ホップごとのトレース、Via、元のステータス、およびネゴシエーションヘッダーを比較します。必要に応じてオリジンに対して直接再現を試みます。
フォローアップ 4: エラーはキャッシュされるべきですか?
Cache-Control に従い、ループの増幅を防止します。修復後は影響を受ける古いエントリをパージします。