Javaのシステムで外部通信時に表題のエラーを調査したのでメモしておきます。
再現方法確認
参考URLにあるような記事を見る限りJava標準のHttpClientの挙動っぽい
とりあえず、Docker&Javaで再現できるか準備して試してみ
dockerfile
FROM amazoncorretto:17
# 作業ディレクトリを設定
WORKDIR /app
# Javaソースコードをコンテナ内にコピー
COPY TestNG.java .
# ソースコードをコンパイル
RUN javac Test.java
# コンテナ起動時に実行するコマンド
CMD ["java", "Test"]
Test.java
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.URI;
import java.net.URISyntaxException;
import java.time.Duration;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws URISyntaxException, IOException, InterruptedException {
// 送信するJSON文字列
String json = """
{
"id": "xxx"
}
""";
final var request = HttpRequest.newBuilder()
.uri(new URI("http://xxxxxxxxxxxxxxxx/yyyyy/zzzzz"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(json))
.timeout(Duration.ofSeconds(10))
.build();
// HttpClientを準備
var httpClient = HttpClient.newBuilder().build();
// リクエスト送信とレスポンス受信
var response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println("Status code: " + response.statusCode());
System.out.println("Response body: " + response.body());
}
}
これで再現は問題無くできたので、次は問題点の修正を確認
$ docker build -t testapp .
--- 省略 ---
$ docker run --rm testapp java Test
Exception in thread "main" java.io.IOException: HTTP/1.1 header parser received no bytes
at java.net.http/jdk.internal.net.http.HttpClientImpl.send(HttpClientImpl.java:591)
at java.net.http/jdk.internal.net.http.HttpClientFacade.send(HttpClientFacade.java:123)
at Test.main(Test.java:29)
--- 省略 ---
対策
ネットの情報では、HTTP1.1を明示する必要があるとあったので試してみたらエラーが発生しなくなった
先ほどのTest.javaの修正点は以下の通り
Test.java変更点
- // HttpClientを準備
- var httpClient = HttpClient.newBuilder().build();
+ // HttpClientを準備
+ var httpClient = HttpClient.newBuilder()
+ .version(HttpClient.Version.HTTP_1_1) // 明示的に HTTP/1.1 を使うように設定
+ // .version(HttpClient.Version.HTTP_2) // デフォルトの挙動はこちらっぽい、これを使用すると同様のエラーが発生した
+ .build();
参考