代表的な面接トピック

一般面接:HTTPサーバーはどのような場合に 426 Upgrade Required を返すべきか?

一般難しい
Offer.cc 編集チーム公開日 更新日

質問

APIゲートウェイがクライアントにHTTP/3の使用を要求しているものの、HTTP/1.1のリクエストを受信しました。426を返すべきタイミング、レスポンスに含めるべき内容、クライアントのリカバリ方法、そしてすべてのプロトコル不一致を426にすべきではない理由を説明してください。

プロンプトとコンテキスト

APIゲートウェイがクライアントにHTTP/3の使用を要求しているものの、HTTP/1.1のリクエストを受信しました。426を返すべきタイミング、レスポンスに含めるべき内容、クライアントのリカバリ方法、そしてすべてのプロトコル不一致を426にすべきではない理由を説明してください。

HTTP 426は、サーバーが現在のプロトコルを使用したリクエストの実行を拒否するものの、クライアントがアップグレードした後は実行する可能性があることを意味します。RFC 9110ではUpgrade: HTTP/3.0を用いた例が示されています。これは実行可能なプロトコルアップグレードの要求であり、汎用的なパラメータエラーやTLSハンドシェイクの失敗、あるいはサーバーがそのリソースをまったく処理できないことの証明ではありません。

面接官がテストしていること

面接官は、426の正確なセマンティクス、UpgradeフィールドとTLSまたはHTTPバージョンネゴシエーションとの境界、そしてキャッシュ、プロキシ、冪等なリトライ、テレメトリ、クライアントの互換性の処理についてテストしています。また、400、421、505を適切に区別できるかも問われます。

明確化のための質問

アップグレードの対象がHTTPなのか、TLS接続なのか、それともアプリケーションのバージョンなのかを確認します。また、クライアントが対象プロトコルを確立できるか、そのメソッドが安全にリトライ可能か、ゲートウェイの手前にプロキシが存在するか、元のリクエストを再送信する必要があるかを確認します。一部のテナントを古いプロトコルのまま残す必要があるか、カナリアリリースやロールバックが必要かも質問してください。

30秒の回答

「現在のプロトコルではサーバーがリソースを処理できないものの、サポートされている対象プロトコルであれば処理できる場合にのみ426を返します。レスポンスには明示的なUpgrade値と、人間または機械が読み取り可能な説明を含める必要があります。クライアントはリトライすべきかを判断する前に対象の接続を作成しなければならず、リクエストが実行されなかったと思い込んではいけません。完全に未対応のHTTPバージョンは505、ルーティングの不一致は421の可能性があり、通常の構文エラーは400です。ゲートウェイはプロトコル、プロキシチェーン、アップグレード結果、キャッシュの挙動、リトライ増幅を追跡すべきです。」

詳細解説

ステップ 1: トリガー条件を確認する

本質的な条件は「現在のプロトコルは不適切だが、アップグレードすれば成功する可能性がある」ことです。サーバーには既知の対象プロトコルと実際のアップグレードパスが必要です。未知のクライアント、不足しているフィールド、古いアプリケーションバージョンは自動的に対象とはなりません。

ステップ 2: レスポンスを実行可能(actionable)にする

サーバーが受け入れるプロトコル(HTTP/3.0など)を記載したUpgradeフィールドに加えて、短いボディまたは機械可読なエラーコードを含めます。曖昧な「アップグレードしてください」というメッセージのみを返したり、内部トポロジーを露出させたりしてはいけません。

http
HTTP/1.1 426 Upgrade Required
Upgrade: HTTP/3.0
Content-Type: application/problem+json

{"type":"https://example.test/problems/upgrade-required","title":"Upgrade required"}

ステップ 3: 接続アップグレードとアプリケーションリトライを分離する

クライアントはまず対象プロトコルの接続を確立し、その後に元のリクエストを再送するかどうかを決定します。接続のアップグレードはトランスポートまたはプロトコルレベルのアクションであり、アプリケーションフィールドの変更ではありません。非冪等なPOSTの場合、クライアントには冪等性キー、実行状態の照会、およびAPI固有のリトライ規約が必要です。

ステップ 4: TLSを適切なレイヤーに保つ

426はTLSハンドシェイクや証明書エラーを代替するものではありません。RFC 2817ではHTTP/1.1からTLSへのアップグレードについて議論されていますが、最新のデプロイでは通常、接続確立時にTLSとHTTPバージョンをネゴシエーションします。リクエストがHTTPレスポンスを生成できる段階に達していない場合は、無理に426を作るのではなくハンドシェイクの失敗として記録してください。

ステップ 5: ステータスコードの境界を定める

400は無効なリクエスト構文またはコンテンツを意味します。421はリクエストに対するレスポンスを生成できないサーバーにリクエストが到達したことを意味します。505はリクエストで使用されたHTTPバージョンをサーバーがサポートしていないことを意味します。426はアップグレード後の継続可能性を約束するものであるため、利用できない対象プロトコルや存在しないリソースを隠蔽するために使用すべきではありません。

ステップ 6: プロキシ、キャッシュ、リトライの挙動を設計する

プロキシが接続を終端して別のリクエストを作成する場合があり、クライアントは自動的にリトライする可能性があります。共有キャッシュが移行エラーを無期限に保持しないよう、意図的なCache-Controlポリシーを指定します。元のプロトコル、ネゴシエーション結果、プロキシチェーン、リトライ回数を記録してください。リトライバジェットはレート制限やサーキットブレーカーと整合させます。

ステップ 7: カナリアリリースとロールバックを保護する

対象プロトコルを使用できるクライアントに対してカナリアリリースを実施し、成功率、レイテンシ、エラーの種類、重複書き込みを監視した上で展開を拡大します。移行が完了するまで古いプロトコルを維持し、クライアント、テナント、またはリージョンごとのロールバックを準備してください。中間者がレスポンスを消費または書き換える可能性があるため、426のカウント数だけでは成功の証拠になりません。

ステップ 8: クライアントのリカバリを検証する

GET、冪等なPUT、非冪等なPOST、長時間接続、プロキシ転送、キャッシュヒット、TLS障害、未知のアップグレード値、利用不可能な対象プロトコルをテストします。再接続、重複書き込み、認証コンテキスト、および426、421、505、ハンドシェイク障害を区別するテレメトリを検証してください。

模範解答

まず、現在のプロトコルがリソースの処理を実際に阻害しており、対象プロトコルが利用可能で明確なアップグレードパスが存在することを確認します。その後、内部の詳細を漏らすことなく、Upgrade: HTTP/3.0と機械可読なエラーを含む426を返します。クライアントはHTTP/3を確立し、リトライ前にメソッドの冪等性、冪等性キー、実行状態の照会を使用しなければなりません。元の書き込みが発生しなかったと勝手に推測することはできません。TLSハンドシェイクの失敗は接続レイヤーに属し、完全に未対応のHTTPバージョンは505、ルーティングの不一致は421、不正なリクエストは400となります。クライアントのケイパビリティに基づいてカナリアリリースを行い、プロトコル、プロキシチェーン、重複書き込み、成功率を監視し、キャッシュとリトライの境界を設定して、古いプロトコルへのロールバックパスを維持します。テストではメソッド、プロキシ、キャッシュ、長時間接続、利用不可能な対象プロトコルを網羅します。

よくある間違い

426を古いクライアント全般の汎用エラーとして扱う

426は、同じリソースを提供できる可能性のあるプロトコルアップグレードに関するものです。古いアプリケーションバージョン、不足しているフィールド、拒否された権限には、それぞれ独自のアプリケーション規約が必要です。

Upgradeフィールドが自動的にアップグレードを実行すると仮定する

レスポンスはクライアントに次に何をすべきかを伝えるだけです。適切な接続を作成するのは依然としてクライアントです。サーバーとプロキシは、対象プロトコル、認証、ルーティング、制限、テレメトリをサポートしていなければなりません。

非冪等なリクエストを自動的に再送する

426はリクエスト処理の境界付近で発生する可能性があります。冪等性キーや実行状態の照会がないままPOSTを再送すると、重複した副作用が発生する恐れがあります。

フォローアップの質問と回答

426と505の決定的な違いは何ですか?

426はアップグレードによってリクエストが成功する可能性があることを示し、対象プロトコルを指定します。505はサーバーがリクエストで使用されたHTTPバージョンをサポートしていないことを示し、通常はアップグレードの約束を行いません。

エッジプロキシがHTTP/3を終端する場合、オリジンは依然として426を返せますか?

エッジがその境界でネゴシエーションとルーティングを処理し、必要なコンテキストをオリジンに渡す必要があります。オリジンが実際のクライアントプロトコルを確認できない場合は、接続フィールドからそれを推測すべきではありません。代わりにプロキシプロトコルと転送セマンティクスを記録してください。

426レスポンスはキャッシュできますか?

キャッシュキー、クライアントのケイパビリティ、移行計画が明確な場合に限られます。デフォルトでは、共有キャッシュがプロトコル移行エラーを長期間保持しないようにし、レスポンスフィールドで短期間のポリシーを表現すべきです。

POSTリクエストはどのようにして426から安全にリカバリできますか?

冪等性キー、実行状態の照会、クライアントのリトライバジェットを使用します。まず対象の接続を確立し、次に元のリクエストが実行されたかどうかを確認します。確認できない場合は、盲目的に再送するのではなく、保留(pending)状態を報告してください。

426を返すのではなく、接続を切断すべきなのはどのような場合ですか?

HTTPレスポンスを生成できるようになる前にTLS、ALPN、または下位レイヤーのプロトコルネゴシエーションが失敗した場合は、接続を閉じてその理由を記録します。426を返すには、送信可能なHTTPレスポンスと実行可能なアップグレードの提案が必要です。

移行がユーザーに悪影響を与えなかったことをどのように証明しますか?

クライアントのケイパビリティごとにカナリアリリースを実施し、426送信後の成功率、レイテンシ、重複書き込み、認証失敗、プロキシの分布、ロールバック時間を比較します。単に426レスポンスをカウントするのではなく、エッジ、オリジン、クライアントのリトライをメトリクス上で分離して計測する必要があります。

公開情報ソース

関連する質問