1. 概述
在这个教程中,我们将展示如何在Java 11及更高版本中使用新的HTTP客户端设置超时。如果需要复习基础知识,可以从Java HTTP客户端教程开始。
另一方面,如果你想了解如何使用旧库设置超时,请参考*HttpUrlConnection*。
2. 设置超时
首先,我们需要创建一个HttpClient
来执行HTTP请求:
private static HttpClient getHttpClientWithTimeout(int seconds) {
return HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(seconds))
.build();
}
上面的方法返回一个配置了参数定义的超时时间的HttpClient
。简而言之,我们使用构建器模式来实例化HttpClient
,并通过connectTimeout
方法配置超时。此外,我们使用静态方法ofSeconds
创建一个Duration
对象实例,用以定义我们的超时时间(以秒为单位)。
接下来,我们需要检查HttpClient
的超时设置是否正确:
httpClient.connectTimeout().map(Duration::toSeconds)
.ifPresent(sec -> System.out.println("Timeout in seconds: " + sec));
我们使用connectTimeout
方法获取超时设置。结果是一个包含Duration
的可选值,我们将其转换为秒。
3. 处理超时
然后,我们需要创建一个HttpRequest
对象,供客户端用于发送HTTP请求:
HttpRequest httpRequest = HttpRequest.newBuilder()
.uri(URI.create("http://10.255.255.1")).GET().build();
为了模拟超时,我们可以调用一个不可路由的IP地址。换句话说,所有TCP包都会被丢弃,并在先前配置的预定义时间内强制超时。
现在,让我们深入了解如何处理超时。
3.1. 处理同步请求超时
例如,对于同步请求,可以使用send
方法:
HttpConnectTimeoutException thrown = assertThrows(
HttpConnectTimeoutException.class,
() -> httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString()),
"Expected send() to throw HttpConnectTimeoutException, but it didn't");
assertTrue(thrown.getMessage().contains("timed out"));
同步请求会强制捕获IOException
,而HttpConnectTimeoutException
是其子类。因此,在上述测试中,我们期望得到带有错误消息的HttpConnectTimeoutException
。
3.2. 处理异步请求超时
同样,对于异步请求,可以使用sendAsync
方法:
CompletableFuture<String> completableFuture = httpClient.sendAsync(httpRequest, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.exceptionally(Throwable::getMessage);
String response = completableFuture.get(5, TimeUnit.SECONDS);
assertTrue(response.contains("timed out"));
对sendAsync
的调用返回一个CompletableFuture<HttpResponse>
。因此,我们需要定义如何从响应功能上处理它。具体来说,如果没有错误发生,我们从响应中获取主体;否则,从throwable中获取错误消息。最后,我们等待最多5秒从CompletableFuture
中获取结果。再次强调,这个请求在3秒后预期会抛出HttpConnectTimeoutException
。
4. 在请求级别配置超时
在前面的例子中,我们重用了同一个客户端实例进行同步和异步请求。然而,我们可能希望为每个请求处理不同的超时。同样,我们可以为单个请求设置超时:
HttpRequest httpRequest = HttpRequest.newBuilder()
.uri(URI.create("http://10.255.255.1"))
.timeout(Duration.ofSeconds(1))
.GET()
.build();
同样地,我们使用timeout
方法为这次请求设置超时。这里,我们为这次请求配置了1秒的超时时间。
客户端到请求之间的最小持续时间决定了请求的超时时间。
5. 总结
在这篇文章中,我们成功地使用新的Java HTTP客户端配置了超时,并在超时溢出时优雅地处理请求。
如往常一样,示例代码可以在GitHub上找到。