## 为何选用 HttpClient
- 标准库组件(Java 11 引入,Java 21 稳定),无需三方依赖。
- 支持 HTTP/2 与连接复用;统一 `send` 阻塞与 `sendAsync` 异步模型。
## 客户端配置示例
import java.net.http.*;
import java.net.http.HttpClient.*;
import java.time.*;
HttpClient client = HttpClient.newBuilder()
.version(Version.HTTP_2)
.connectTimeout(Duration.ofSeconds(3))
.followRedirects(Redirect.NORMAL)
.build();
请求级超时:
HttpRequest req = HttpRequest.newBuilder()
.uri(java.net.URI.create("https://example.com/api"))
.timeout(Duration.ofSeconds(2))
.GET()
.build();
## 方案一:虚线程 + 阻塞 send
- 思路:用虚线程承载阻塞 I/O,写法直观;HttpClient 负责连接复用。
import java.util.concurrent.*;
import java.net.http.*;
ExecutorService es = Executors.newVirtualThreadPerTaskExecutor();
HttpClient client = HttpClient.newHttpClient();
Callable<Integer> task = () -> {
HttpRequest r = HttpRequest.newBuilder(java.net.URI.create("https://example.com/api/1")).build();
HttpResponse<String> resp = client.send(r, HttpResponse.BodyHandlers.ofString());
return resp.statusCode();
};
Future<Integer> f1 = es.submit(task);
Future<Integer> f2 = es.submit(task);
System.out.println(f1.get());
System.out.println(f2.get());
es.close();
注意:
- 虚线程不消除下游限流/队列饱和;需结合并发信号量或速率限制。
- 在同一 `HttpClient` 上复用连接;避免每次新建客户端导致握手开销。
## 方案二:sendAsync + CompletableFuture
- 思路:使用非阻塞 API,结合 `CompletableFuture` 聚合结果。
import java.net.http.*;
import java.util.*;
import java.util.concurrent.*;
HttpClient client = HttpClient.newHttpClient();
List<CompletableFuture<HttpResponse<String>>> futures = new ArrayList<>();
for (int i = 0; i < 10; i++) {
HttpRequest r = HttpRequest.newBuilder(java.net.URI.create("https://example.com/api/" + i)).build();
futures.add(client.sendAsync(r, HttpResponse.BodyHandlers.ofString()));
}
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
futures.forEach(f -> System.out.println(f.join().statusCode()));
并发限流(示例用信号量):
Semaphore gate = new Semaphore(100);
CompletableFuture<HttpResponse<String>> limited(HttpRequest r) {
return CompletableFuture.supplyAsync(() -> {
try {
gate.acquire();
return client.send(r, HttpResponse.BodyHandlers.ofString());
} catch (Exception e) {
throw new CompletionException(e);
} finally {
gate.release();
}
});
}
## 连接复用与 HTTP/2
- 复用同一 `HttpClient` 以保持连接池有效;HTTP/2 允许多路复用,降低队头阻塞。
- TLS 会话可复用与 0-RTT(取决于服务器配置);避免频繁创建新连接。
## 超时、重试与健壮性
- 连接超时:`HttpClient.connectTimeout`;请求超时:`HttpRequest.timeout`。
- 自动重试需自行实现(如基于响应码与异常类别的指数退避策略);注意幂等性。
- 对下游做舱壁与熔断,避免单点故障扩散。
## 验证建议
- 指标:P50/P95/P99 延迟、吞吐、错误率;对比虚线程方案与 `sendAsync`。
- 采集:GC 日志与 JFR;同时记录服务器端指标,避免客户端伪影。
- 单因素变更:固定并发与负载,仅切换模型,以便归因。
## 注意事项
- 关键词与主题一致:Java 21、HttpClient、虚线程、`sendAsync`、连接复用与限流。
- 分类匹配:`软件/编程语言/Java`。
- 描述准确:涵盖配置、并发模型与验证方法。
- 技术参数已验证:示例 API 为 Java 标准库;HTTP/2 与超时配置来源于 `HttpClient` 正式特性。

发表评论 取消回复