Java11 HTTP客户端案例

wen java案例 1

Java 11 HTTP客户端实战:从入门到性能调优的完整指南

目录导读

  1. 为什么还要学Java 11的HttpClient? (对比旧API的痛点)
  2. 五分钟快速上手:发送你的第一个GET请求
  3. 核心API拆解:HttpRequest、HttpResponse与BodyPublisher
  4. 进阶玩法:同步 vs 异步请求,以及超时与重试
  5. 实战案例:RESTful API调用 + JSON解析(含代码)
  6. 性能优化技巧:连接池、HTTP/2与压缩
  7. 常见问题FAQ(附解答)

为什么还要学Java 11的HttpClient?

自从Java 11正式将java.net.http.HttpClient纳入标准库后,开发者终于告别了HttpURLConnection那个“老古董”,也无需再为简单的请求引入Apache HttpClient或OkHttp。核心优势

Java11 HTTP客户端案例

  • 原生支持HTTP/2,底层自动多路复用,减少延迟。
  • 响应式流(Reactive Streams),支持异步非阻塞。
  • 内置WebSocket支持,无需额外依赖。
  • 简洁流畅的API设计,比HttpURLConnection可读性强10倍。

根据JetBrains 2023年调查,超过42%的Java开发者已在生产环境使用该API,因为它能显著降低依赖冲突和内存占用。

五分钟快速上手:发送你的第一个GET请求

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class QuickStart {
    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://api.github.com/repos/openjdk/jdk"))
                .header("Accept", "application/json")
                .GET()
                .build();
        HttpResponse<String> response = client.send(request, 
                HttpResponse.BodyHandlers.ofString());
        System.out.println("状态码: " + response.statusCode());
        System.out.println("响应体: " + response.body().substring(0, 100));
    }
}

注意:如果目标URL是http://而非https://,则无需额外证书配置,这段代码即可完成联网通信,无需任何第三方库。

核心API拆解

1 HttpRequest 构建器

采用建造者模式,支持链式调用:

  • .uri():必填,指定目标地址。
  • .header() / .headers():添加请求头(可重复调用以添加多个)。
  • .timeout(Duration):设置请求超时,否则会一直阻塞。
  • .POST(BodyPublishers.ofString(json)) / .PUT(...):指定方法及请求体。

2 HttpResponse 响应处理

  • statusCode():HTTP状态码。
  • headers():返回HttpHeaders对象,可通过firstValue("Content-Type")获取某头。
  • body():基于BodyHandler的解码结果,常用ofString()ofByteArray()ofInputStream()

3 BodyPublisher(请求体发布者)

  • ofString():普通字符串。
  • ofByteArray():二进制数据。
  • ofInputStream():流式上传大文件,避免OOM。

进阶玩法:同步 vs 异步 + 超时重试

1 异步请求

CompletableFuture<HttpResponse<String>> future = 
    client.sendAsync(request, HttpResponse.BodyHandlers.ofString());
future.thenAccept(resp -> System.out.println(resp.body()));

异步返回CompletableFuture,便于编排多个请求并行执行,例如使用allOf等待所有完成。

2 超时设置

HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("https://example.com/slow"))
        .timeout(Duration.ofSeconds(5))
        .GET().build();

超时后抛出HttpTimeoutException

3 重试机制(简易版)

int maxRetries = 3;
for (int i = 1; i <= maxRetries; i++) {
    try {
        return client.send(request, BodyHandlers.ofString());
    } catch (IOException e) {
        if (i == maxRetries) throw e;
        Thread.sleep(1000 * i); // 指数退避
    }
}

生产建议使用Resilience4jSpring Retry

实战案例:调用REST API并解析JSON(无第三方库)

以获取比特币价格为例(CoinDesk API):

public class CryptoPriceFetcher {
    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newBuilder()
                .connectTimeout(Duration.ofSeconds(10))
                .build();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://api.coindesk.com/v1/bpi/currentprice.json"))
                .GET().build();
        HttpResponse<String> response = client.send(request, 
                HttpResponse.BodyHandlers.ofString());
        // 手动解析(简单演示,实际可用Jackson/Gson)
        String json = response.body();
        String usdPrice = json.split("\"rate\":\"")[1].split("\"")[0];
        System.out.println("BTC价格 (USD): " + usdPrice);
    }
}

输出示例BTC价格 (USD): 63,412.5875(价格实时浮动)。

性能优化技巧

1 复用HttpClient实例

HttpClient是线程安全的,务必复用,每次newHttpClient()会新建连接池,浪费资源。

2 启用HTTP/2

默认已启用,但需确认服务器支持,可通过client.version(HttpClient.Version.HTTP_2)强制指定,若握手失败自动降级为HTTP/1.1。

3 连接池大小调整

HttpClient client = HttpClient.newBuilder()
        .executor(Executors.newFixedThreadPool(10)) // 自定义线程池
        .build();

默认使用ForkJoinPool.commonPool(),高并发场景建议自定线程数。

4 启用Gzip压缩

request = HttpRequest.newBuilder(request, 
        (name, value) -> true) // 保留原请求头
        .header("Accept-Encoding", "gzip")
        .build();

但注意,BodyHandlers.ofString()不会自动解压,需使用ofInputStream()并处理GZIP流。

常见问题FAQ

Q1: Java 8或更低版本能用吗? 不能,该API从Java 11才正式引入,若必须用Java 8,可用OkHttp或Apache HttpClient。

Q2: 为什么我发送POST请求时,服务器说没有收到body? 请检查你是否调用了.POST(BodyPublishers.ofString(...)),如果只设置.method("POST", BodyPublishers.noBody()),则不会发送请求体。

Q3: 如何携带Cookie? 通过.header("Cookie", "sessionId=abc123"),或者使用CookieManager

CookieManager cm = new CookieManager();
HttpClient client = HttpClient.newBuilder()
        .cookieHandler(cm).build();

Q4: 遇到SSLHandshakeException怎么办? 一般是证书链不完整或自签名,开发环境可临时信任所有证书(不推荐生产),或使用System.setProperty("javax.net.ssl.trustStore", "...")

Q5: 上传大文件会不会内存溢出? 使用BodyPublishers.ofInputStream(() -> new FileInputStream(file)),它将流式读取,不加载全量到内存。


Java 11的HttpClient足以满足日常微服务调用、爬虫脚本、集成测试等场景,掌握其同步/异步、超时重试、连接复用这些核心操作,能让你写出更健壮的网络层代码,从今天起,试着用这个原生API替换掉那些笨重的第三方库吧。

抱歉,评论功能暂时关闭!