505 HTTP Version Not Supported:その「断絶」はどこで起きているのか?
ネットワークの現場で「505 HTTP Version Not Supported」というエラーを目にすることは、現代のWeb開発において決して多くはありません。しかし、だからこそこのエラーに遭遇したとき、多くのエンジニアは困惑します。「なぜ、今さらプロトコルのバージョンで弾かれるのか?」と。
今日は、この一見古臭い、しかし本質的なエラーについて、プロトコルの深淵から紐解いていこうと思います。
—
505エラーの正体:通信の「握手」が成立しない瞬間
HTTPステータスコード 505 は、サーバーがリクエストで使用されたHTTPプロトコルのメジャーバージョンをサポートしていない、あるいはサポートを拒否したことを示します。
RFC 7231の定義によれば、サーバーはリクエストメッセージの開始行(Start Line)にあるバージョン情報を確認し、自らが対応していないと判断した場合、即座に505を返すべきとされています。これは単なる設定ミスではなく、「クライアントとサーバー間の言語が致命的に噛み合っていない」という宣告です。
発生する典型的なシナリオ
1. レガシーなインフラへのHTTP/2リクエスト: フロントエンドやリバースプロキシが HTTP/2 で通信しようとしているのに、バックエンドのアプリケーションサーバーが HTTP/1.1 までしか理解できない場合。
2. プロトコル・ダウングレードの失敗: セキュリティ要件により古いプロトコルを無効化した後、キャッシュや古いクライアントが過去のバージョンで接続を試みる場合。
3. 不適切なプロキシ/ゲートウェイの介在: 中継する中間のミドルウェアが、クライアントのバージョンをバックエンドに適切に変換・転送できず、生のリクエストをそのまま投げてしまった場合。
—
実践:505を意図的に再現し、通信を可視化する
理論を理解するには、まず「壊してみる」のが一番です。`curl` を使って、あえてサーバーが解釈不能なバージョン(例えば存在しないHTTP/3.0など)を送りつけてみましょう。
意図的に非対応のプロトコルバージョンを指定してリクエストを送る
–http3 は環境によりますが、サーバーがサポートしていないバージョンを
強制的に指定することでサーバーの拒絶を誘発します
curl -I –http3 https://example.com/api/v1/resource
もしサーバーが HTTP/1.1 しか喋れない環境であれば、レスポンスヘッダーには以下のように刻まれます。
HTTP/1.1 505 HTTP Version Not Supported
Date: Wed, 25 Oct 2023 10:00:00 GMT
Server: Apache/2.4.41 (Ubuntu)
Connection: close
サーバーは「そのバージョンでは会話できない」と即座に切断する
—
トラブルシューティングの定石:現場でどう切り分けるか
もしあなたがインフラエンジニアとしてこのエラーに直面したら、以下の手順で「どこで断絶しているか」を特定してください。
1. クライアントとサーバーの間の「翻訳者」を疑う
多くの場合、エラーはバックエンドサーバーではなく、手前のNginxやAWS ALB(Application Load Balancer)といったプロキシ層で発生します。Nginxの設定を確認しましょう。
nginx.conf の例
server {
listen 443 ssl http2; # HTTP/2 を有効化
location / {
# ここでバックエンドにプロキシする際、バージョンが維持されているか確認
proxy_pass http://backend_server;
proxy_http_version 1.1; # バックエンドが HTTP/1.1 なら必須
proxy_set_header Connection “”; # Keep-Alive を維持
}
}
2. Python (requests) での検証用スクリプト
トラブルの切り分けには、あえて生のリクエストを送るスクリプトを書くのが有効です。
import http.client
HTTP/1.1 よりも古いプロトコルをあえて指定するテスト
conn = http.client.HTTPConnection(“your-api-server.com”)
RFC的には HTTP/0.9 は非常に特殊な挙動をするため、
サーバー側で拒否設定されているかをテストできる
conn.request(“GET”, “/”, version=”HTTP/0.9″)
response = conn.getresponse()
print(f”Status: {response.status}”)
print(f”Reason: {response.reason}”)
—
エンジニアへの助言:プロトコルネゴシエーションの限界
HTTP/1.1 から HTTP/2、そして HTTP/3 (QUIC) へと進化する過程で、私たちは「いかに速く、効率的に通信するか」ばかりを追い求めてきました。しかし、プロトコルネゴシエーション(ALPNなど)は万能ではありません。
505 エラーは、「最新の技術スタックとレガシーな資産の境界線」で発生するアラートです。
- API設計者へ: クライアントがどのバージョンで接続してきてもいいように、ゲートウェイ側でプロトコル変換を確実に行うこと。
- 運用担当者へ: サーバーのアップデート時に、旧プロトコルのサポートを無効化する際は、クライアントの接続ログを必ず事前に確認すること。
「動いているから大丈夫」ではなく、「どのプロトコルで会話しているか」を常に意識する。その視点こそが、複雑なマイクロサービスアーキテクチャを支える確かな基盤となります。
もし次に 505 に出会ったら、それは「新しい世界へ踏み出そうとして、古い扉に弾かれた」という合図です。焦らず、プロキシのログを追いかけ、接続の握手を一つずつ解き明かしてください。それが、熟練したエンジニアの流儀です。
コメント