Java HttpClient 超時
- java
一、概述
在本教程中,我們將展示如何使用從 Java 11 開始提供的新 Java HTTP 客戶端和 Java 設置超時。
如果我們需要更新我們的知識,我們可以從 Java HTTP Client 的教程開始。
另一方面,要了解如何使用舊庫設置超時,請參閱HttpUrlConnection.
2.配置超時
首先,我們需要設置一個 HttpClient 才能發出 HTTP 請求:
private static HttpClient getHttpClientWithTimeout(int seconds) {
return HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(seconds))
.build();
}
上面,我們創建了一個方法,該方法返回一個配置了超時定義為參數的HttpClient
。很快,我們使用 Builder 設計模式來實例化一個HttpClient
並使用connectTimeout
方法配置超時。此外,使用靜態方法ofSeconds
,我們創建了一個Duration
對象的實例,它以秒為單位定義我們的超時。
之後,我們檢查HttpClient
超時是否配置正確:
httpClient.connectTimeout().map(Duration::toSeconds)
.ifPresent(sec -> System.out.println("Timeout in seconds: " + sec));
因此,我們使用connectTimeout
方法來獲取超時。結果,它返回一個Duration,
的Optional
,我們將其映射到秒。
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
帶有錯誤消息。
4.在請求級別配置超時
上面,我們為sync
和async
調用重用了相同的客戶端實例。但是,我們可能希望為每個請求以不同的方式處理超時。同樣,我們可以為單個請求設置超時:
HttpRequest httpRequest = HttpRequest.newBuilder()
.uri(URI.create("http://10.255.255.1"))
.timeout(Duration.ofSeconds(1))
.GET()
.build();
同樣,我們使用timeout
方法來設置這個請求的超時時間。在這裡,我們為這個請求配置了 1 秒的超時時間。
客戶端和請求之間的最短持續時間設置請求的超時時間。
5 處理異步調用超時
同樣,要進行異步調用,請使用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
,正如我們預期的那樣。