如何使用Java的HttpClient在慢速流响应主体上超时
当我需要以流方式处理响应时,我应该如何处理使用 Java 11 中包含的 HTTP 客户端挂起发送 HTTP 响应正文的服务器?
已经阅读文档,我知道,这是可以设置在连接超时和在请求超时:
HttpClient httpClient = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(2))
.build();
HttpRequest httpRequest = HttpRequest.newBuilder(URI.create("http://example.com"))
.timeout(Duration.ofSeconds(5))
.build();
HttpResponse<Stream<String>> httpResponse = httpClient
.send(httpRequest, HttpResponse.BodyHandlers.ofLines());
Stream<String> responseLineStream = httpResponse.body();
responseLineStream.count();
在上面的代码中:
- 如果在 2 秒内无法建立连接,则会抛出超时异常。
- 如果在 5 秒内没有收到响应,则会抛出超时异常。通过实验,定时器在连接建立后启动,对于这种类型
BodyHandler,当收到状态行和报头时,就认为收到了响应。
这意味着当代码执行时,在 7 秒内要么抛出异常,要么到达最后一行。但是,最后一行不受任何超时的限制。如果服务器停止发送响应正文,最后一行将永远阻塞。
在这种情况下,如何防止最后一行挂起?
回答
我的猜测是留给流的消费者,因为这是处理逻辑的一部分,所以身体处理仍然可以用以下方式处理CompletableFuture:
HttpResponse<Stream<String>> httpResponse = httpClient.send(httpRequest,
HttpResponse.BodyHandlers.ofLines());
Stream<String> responseLineStream = httpResponse.body();
CompletableFuture<Long> future = CompletableFuture.supplyAsync(() -> responseLineStream.count());
long count = future.get(3, TimeUnit.SECONDS);
或者只是简单地Future由 Java 执行Executor。