問題
FastAPIにPOSTリクエストを送ったところ、なぜかJavaからだけ失敗しました。
FastAPI(Uvicorn)のログには次のようなメッセージが出ていました。
WARNING: Unsupported upgrade request.
INFO: 127.0.0.1:52769 - "POST /api/search HTTP/1.1" 422 Unprocessable Content
WARNING: Invalid HTTP request received.
一方で、Pythonの requests.post() では正常に成功します。
発生していたコード
Javaでは HttpClient を使ってFastAPIへリクエストを送っていました。
HttpRequest request =
HttpRequest.newBuilder()
.uri(URI.create(BASE_URL + path))
.header(
"Content-Type",
"application/json")
.POST(
HttpRequest.BodyPublishers
.ofString(json))
.build();
HttpResponse<String> response =
httpClient.send(
request,
HttpResponse.BodyHandlers.ofString());
一見問題なさそうに見えます。
しかしFastAPI側では422エラーになり、さらに次の警告が出ていました。
Unsupported upgrade request.
Invalid HTTP request received.
原因
原因は、Javaの HttpClient がデフォルトでHTTP/2を優先することでした。
例えば次のコードで生成した HttpClient は、
HttpClient httpClient =
HttpClient.newHttpClient();
内部的にHTTP/2を優先します。
FastAPIを動かしているUvicornとの組み合わせによっては、HTTP/2へのUpgrade要求が正しく処理されず、
Unsupported upgrade request.
Invalid HTTP request received.
という警告が出ることがあります。
その結果、FastAPI側でリクエストが正常に解釈できず、422エラーになっていました。
解決方法
HTTP/1.1を明示的に指定します。
private final HttpClient httpClient =
HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_1_1)
.build();
これだけで正常にPOSTできるようになりました。
まとめ
Javaの HttpClient からFastAPIへPOSTしたときに、
Unsupported upgrade request.
Invalid HTTP request received.
が出る場合は、HTTPバージョンを疑ってみるとよいです。
HttpClient.newHttpClient() を使っている場合は、
.version(HttpClient.Version.HTTP_1_1)
を指定することで解決する可能性があります。