## 为何选用 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` 正式特性。


点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部