Java HTTP客户端:正确发送请求(高级水平)
处理HTTP请求是现代Java开发中的基本任务之一。然而,编写不仅能发送请求,还能可靠地处理错误、超时和资源管理的代码,需要深入的理解。在本文中,我们将超越简单的HttpURLConnection,深入探讨使用内置java.net.http.HttpClient(Java 11+)和流行库OkHttp进行Java HTTP客户端的高级技术。
1. 超时管理:防止应用程序挂起
处理HTTP时最常见的问题之一是由于服务器响应慢或不可用而导致应用程序挂起。正确配置超时是创建容错客户端的第一步。
超时类型:
- 连接超时:等待与服务器建立TCP连接的时间。
- 读取超时(套接字超时):建立连接后等待服务器数据的时间。
- 写入超时:等待向服务器发送数据的时间(适用于POST/PUT)。
- 请求超时:整个HTTP请求的总执行时间(包括连接、发送和接收响应)。
java.net.http.HttpClient 配置示例:
import java.net.http.HttpClient;import java.time.Duration;
public class TimeoutExample { public static HttpClient createClientWithTimeouts() { return HttpClient.newBuilder() .connectTimeout(Duration.ofSeconds(5)) // 连接超时 .build(); }
public static void main(String[] args) { HttpClient client = createClientWithTimeouts(); // 对于读取/写入超时,使用 HttpRequest var request = java.net.http.HttpRequest.newBuilder() .uri(java.net.URI.create("https://api.example.com/data")) .timeout(Duration.ofSeconds(10)) // 请求总超时 .GET() .build(); System.out.println("带超时的客户端已创建: " + client); }}OkHttp 配置示例:
import okhttp3.OkHttpClient;import java.util.concurrent.TimeUnit;
public class OkHttpTimeoutExample { public static OkHttpClient createOkHttpClient() { return new OkHttpClient.Builder() .connectTimeout(5, TimeUnit.SECONDS) .readTimeout(10, TimeUnit.SECONDS) .writeTimeout(10, TimeUnit.SECONDS) .callTimeout(30, TimeUnit.SECONDS) // 整个调用的总超时 .build(); }
public static void main(String[] args) { OkHttpClient client = createOkHttpClient(); System.out.println("带超时的OkHttp客户端已准备好工作。"); }}2. 连接池与复用:节省资源
每个新的HTTP连接都需要建立TCP握手,可能还需要TLS握手的开销。对于向同一服务器发送大量请求的应用程序,使用连接池至关重要。这允许复用现有连接,从而显著加快请求速度并降低网络负载。
java.net.http.HttpClient 内置了连接池,自动管理。但您可以配置其大小:
import java.net.http.HttpClient;import java.net.http.HttpRequest;import java.net.http.HttpResponse;import java.net.URI;import java.time.Duration;
public class PoolExample { public static void main(String[] args) throws Exception { // HttpClient 自行管理连接池,但我们可以限制