背景:Transfer-Encoding: chunked とは?
HTTP で Transfer-Encoding: chunked が使われると、ボディは「チャンク(塊)」に分割されて送られます。この形式では、Content-Length ヘッダーは使われません。
Java の HttpClient はこのチャンク化されたレスポンスを自動で扱うことができますが、処理の書き方によってはボディを正しく読めないことがあります。
確認ポイント(受信側)
1.BodyHandler の指定
HttpClient.send() でレスポンスを受け取る際、以下のようにしてますか?
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
これがない、あるいは BodyHandlers.discarding() を使っていると、ボディは読み込まれません。
2.InputStream で受け取って自前で読む方法
Chunked エンコーディングに問題があると感じた場合は、ofInputStream() で受け取り、自前で確認するのも手です:
HttpResponse<InputStream> response = client.send(request, HttpResponse.BodyHandlers.ofInputStream());
try (BufferedReader reader = new BufferedReader(new InputStreamReader(response.body(), StandardCharsets.UTF_8))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
これで実際にチャンクが届いているか確認できます。
3. サーバーが Transfer-Encoding: chunked を明示的に設定しているか
HttpServer の実装で Transfer-Encoding: chunked を自分で追加している場合、それが誤ったフォーマットになっている可能性があります。
Java の com.sun.net.httpserver.HttpServer などでは、ボディサイズが不明なときに自動で chunked にしてくれることもあります。ヘッダーを手動でいじる場合は注意が必要です。
確認ポイント(送信側:HttpServer)
HttpExchange を使っていると仮定して、以下のように書くのが一般的です:
exchange.getResponseHeaders().set("Content-Type", "text/plain; charset=UTF-8");
exchange.sendResponseHeaders(200, 0); // ← 0 を指定すると chunked エンコーディングになる
OutputStream os = exchange.getResponseBody();
os.write("Hello chunked world".getBytes(StandardCharsets.UTF_8));
os.close();
ポイント:
sendResponseHeaders(200, 0):この 0 は「ボディサイズが不明」を意味し、自動で chunked にしてくれる。
自分で Transfer-Encoding: chunked をヘッダーに追加しても、それだけでは機能しません。正しくチャンク形式で送信される必要があります。