当前位置: 首页 > news >正文

探索 Java 中的新 HTTP 客户端

你是否也遇到过这样的时刻:只是想发个 HTTP 请求,却被连接管理、重定向、超时与线程阻塞折腾得不亦乐乎?那就试试 Java 11 正式标准化了全新的 HttpClient,原生支持 HTTP/2、异步与 WebSocket,极大简化了客户端网络编程。

1. 概览

本文将介绍 Java 11 对全新HTTP 客户端 API(支持 HTTP/2 与 WebSocket)的标准化。

它旨在替代 JDK 早期就存在的旧类HttpURLConnection(文档见:https://docs.oracle.com/en/java/javase/21/docs/api/java.base/...)。

在不久之前,Java 只有较为底层、功能有限且不够友好的HttpURLConnectionAPI。因此社区普遍使用第三方库,如 Apache HttpClient、Jetty 以及 Spring 的 RestTemplate。

2. 背景

该变更由 JEP 321 引入并最终在 Java 11 中定型。

2.1. JEP 321 的主要变更

  1. Java 9 的孵化版 HTTP API 已正式并入 Java SE API。新的 HTTP APIs 位于java.net.http.*
  2. 新版本的 HTTP 协议旨在提升客户端请求与服务器响应的整体性能,包括多路复用、头压缩与推送承诺(push promise)等特性。
  3. 自 Java 11 起,API 全面支持异步(相比之下,旧的 HTTP/1.1 实现是阻塞式的)。异步以CompletableFuture实现,阶段式流水线在前一阶段完成后自动衔接执行。
  4. 新的 HTTP 客户端提供了标准方式执行网络操作,原生支持现代 Web 能力(如 HTTP/2),无需引入第三方依赖。
  5. 新 API 原生支持 HTTP/1.1 与 HTTP/2 的 WebSocket。核心类型包括:

    • HttpClientjava.net.http.HttpClient
    • HttpRequestjava.net.http.HttpRequest
    • HttpResponse<T>java.net.http.HttpResponse
    • WebSocketjava.net.http.WebSocket

2.2. Java 11 之前客户端的问题

旧版HttpURLConnection及其实现存在诸多问题:

  • URLConnection为多个如今已不再使用的协议(FTP、gopher 等)而设计;
  • API 早于 HTTP/1.1,抽象层级不合时宜;
  • 仅支持阻塞模式(一次请求/响应占用一个线程);
  • 维护困难。

3. HTTP Client API 总览

HttpURLConnection不同,新 HTTP 客户端同时提供同步与异步两种请求机制。

API 的三大核心:

  • HttpRequest:要发送的请求;
  • HttpClient:跨请求的通用配置容器;
  • HttpResponse:请求的响应结果。

下面分别展开,先从请求开始。

4. HttpRequest

HttpRequest表示将要发送的请求,可通过HttpRequest.newBuilder()获取构建器;构建器提供多种便捷方法配置请求。

注:JDK 16 新增HttpRequest.newBuilder(HttpRequest request, BiPredicate<String,String> filter),可基于已有请求复制初始状态,再在构建前做修改(如移除部分头):

HttpRequest.newBuilder(request, (name, value) -> !name.equalsIgnoreCase("Foo-Bar"));

4.1. 设置 URI

可直接用带URI的构造方式,或在构建器上调用uri(URI)

HttpRequest.newBuilder(new URI("https://postman-echo.com/get")); HttpRequest.newBuilder() .uri(new URI("https://postman-echo.com/get"));

4.2. 指定 HTTP 方法

构建器提供以下方法:

  • GET()
  • POST(BodyPublisher body)
  • PUT(BodyPublisher body)
  • DELETE()

一个最简单的 GET 示例:

HttpRequest request = HttpRequest.newBuilder() .uri(new URI("https://postman-echo.com/get")) .GET() .build();

常见的附加参数包括:HTTP 协议版本、请求头与超时。

4.3. 设置协议版本

API 默认充分利用 HTTP/2,也可显式指定:

HttpRequest request = HttpRequest.newBuilder() .uri(new URI("https://postman-echo.com/get")) .version(HttpClient.Version.HTTP_2) .GET() .build();

注意:若对端不支持 HTTP/2,客户端会回退到 HTTP/1.1。

4.4. 设置请求头

可用headers(k1,v1,k2,v2,...)一次性传入,或多次调用header(k,v)

HttpRequest request = HttpRequest.newBuilder() .uri(new URI("https://postman-echo.com/get")) .headers("key1", "value1", "key2", "value2") .GET() .build(); HttpRequest request2 = HttpRequest.newBuilder() .uri(new URI("https://postman-echo.com/get")) .header("key1", "value1") .header("key2", "value2") .GET() .build();

4.5. 设置超时

默认无穷大。可用Duration设置,超时会抛出HttpTimeoutException

HttpRequest request = HttpRequest.newBuilder() .uri(new URI("https://postman-echo.com/get")) .timeout(Duration.ofSeconds(10)) .GET() .build();

5. 设置请求体

POST(BodyPublisher),PUT(BodyPublisher)可携带请求体(DELETE()也支持不带体的删除)。常用的BodyPublisher工厂有:

  • HttpRequest.BodyPublishers.ofString:基于字符串;
  • HttpRequest.BodyPublishers.ofInputStream:基于输入流(以Supplier<InputStream>形式延迟创建);
  • HttpRequest.BodyPublishers.ofByteArray:基于字节数组;
  • HttpRequest.BodyPublishers.ofFile:基于文件路径内容;
  • 无请求体:HttpRequest.BodyPublishers.noBody()

JDK 16 新增BodyPublishers.concat(...),可把多个 publisher 的内容顺序拼接为一个请求体。

5.1. 字符串请求体

HttpRequest request = HttpRequest.newBuilder() .uri(new URI("https://postman-echo.com/post")) .headers("Content-Type", "text/plain;charset=UTF-8") .POST(HttpRequest.BodyPublishers.ofString("Sample request body")) .build();

5.2. 输入流请求体

byte[] sampleData = "Sample request body".getBytes(); HttpRequest request = HttpRequest.newBuilder() .uri(new URI("https://postman-echo.com/post")) .headers("Content-Type", "text/plain;charset=UTF-8") .POST(HttpRequest.BodyPublishers .ofInputStream(() -> new ByteArrayInputStream(sampleData))) .build();

5.3. 字节数组请求体

byte[] sampleData = "Sample request body".getBytes(); HttpRequest request = HttpRequest.newBuilder() .uri(new URI("https://postman-echo.com/post")) .headers("Content-Type", "text/plain;charset=UTF-8") .POST(HttpRequest.BodyPublishers.ofByteArray(sampleData)) .build();

5.4. 文件请求体

HttpRequest request = HttpRequest.newBuilder() .uri(new URI("https://postman-echo.com/post")) .headers("Content-Type", "text/plain;charset=UTF-8") .POST(HttpRequest.BodyPublishers.ofFile( Paths.get("src/test/resources/sample.txt"))) .build();

6. HttpClient

所有请求都由HttpClient发送,可通过HttpClient.newBuilder()HttpClient.newHttpClient()获取。下面看几个常用能力。

6.1. 处理响应体

新的BodyHandlers工厂提供常见类型的响应体处理器:

BodyHandlers.ofByteArray; BodyHandlers.ofString; BodyHandlers.ofFile; BodyHandlers.discarding; BodyHandlers.replacing; BodyHandlers.ofLines; BodyHandlers.fromLineSubscriber;

Java 11 之前:

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandler.asString());

现在可简化为:

HttpResponse<String> response = client.send(request, BodyHandlers.ofString());

6.2. 设置代理

HttpResponse<String> response = HttpClient .newBuilder() .proxy(ProxySelector.getDefault()) .build() .send(request, BodyHandlers.ofString());

6.3. 跟随重定向策略

HttpResponse<String> response = HttpClient.newBuilder() .followRedirects(HttpClient.Redirect.ALWAYS) .build() .send(request, BodyHandlers.ofString());

6.4. 认证器(Authenticator)

HttpResponse<String> response = HttpClient.newBuilder() .authenticator(new Authenticator() { @Override protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication( "username", "password".toCharArray()); } }) .build() .send(request, BodyHandlers.ofString());

6.5. 同步与异步发送

  • 同步:send(...)(阻塞直到响应返回)
  • 异步:sendAsync(...)(立即返回CompletableFuture<HttpResponse<T>>

同步示例:

HttpResponse<String> response = HttpClient.newBuilder() .build() .send(request, BodyHandlers.ofString());

异步示例:

CompletableFuture<HttpResponse<String>> response = HttpClient.newBuilder() .build() .sendAsync(request, HttpResponse.BodyHandlers.ofString());

批量并发请求:

List<URI> targets = Arrays.asList( new URI("https://postman-echo.com/get?foo1=bar1"), new URI("https://postman-echo.com/get?foo2=bar2")); HttpClient client = HttpClient.newHttpClient(); List<CompletableFuture<String>> futures = targets.stream() .map(target -> client .sendAsync( HttpRequest.newBuilder(target).GET().build(), HttpResponse.BodyHandlers.ofString()) .thenApply(HttpResponse::body)) .collect(Collectors.toList());

6.6. 指定异步执行器(Executor)

ExecutorService executorService = Executors.newFixedThreadPool(2); CompletableFuture<HttpResponse<String>> response1 = HttpClient.newBuilder() .executor(executorService) .build() .sendAsync(request, HttpResponse.BodyHandlers.ofString()); CompletableFuture<HttpResponse<String>> response2 = HttpClient.newBuilder() .executor(executorService) .build() .sendAsync(request, HttpResponse.BodyHandlers.ofString());

默认执行器为Executors.newCachedThreadPool()

6.7. CookieHandler

设置客户端级CookieHandler

HttpClient.newBuilder() .cookieHandler(new CookieManager(null, CookiePolicy.ACCEPT_NONE)) .build();

若允许存储 Cookie,可从CookieManager读取:

((CookieManager) httpClient.cookieHandler().get()).getCookieStore();

7. HttpResponse

HttpResponse表示服务端响应,核心方法:

  • statusCode():返回整型状态码;
  • body():返回响应体(类型取决于发送时的BodyHandler)。

其他常用方法还包括uri()headers()trailers()version()

7.1. 响应的 URI

由于重定向,响应返回的uri()可能与请求不同:

assertThat(request.uri().toString(), equalTo("http://stackoverflow.com")); assertThat(response.uri().toString(), equalTo("https://stackoverflow.com/"));

7.2. 响应头

HttpResponse<String> response = HttpClient.newHttpClient() .send(request, HttpResponse.BodyHandlers.ofString()); HttpHeaders responseHeaders = response.headers();

7.3. 响应协议版本

即使请求设置为 HTTP/2,服务端也可能以 HTTP/1.1 响应,实际版本可从响应读取:

HttpRequest request = HttpRequest.newBuilder() .uri(new URI("https://postman-echo.com/get")) .version(HttpClient.Version.HTTP_2) .GET() .build(); HttpResponse<String> response = HttpClient.newHttpClient() .send(request, HttpResponse.BodyHandlers.ofString()); assertThat(response.version(), equalTo(HttpClient.Version.HTTP_1_1));

8. HTTP/2 推送承诺(Push Promise)

新的HttpClient通过PushPromiseHandler支持服务端主动推送。当客户端请求主资源时,服务器可以同时“推送”额外资源,从而减少往返次数、加快页面渲染。该能力得益于 HTTP/2 的多路复用。

如有推送承诺,将由提供的PushPromiseHandler处理;若传入null,则拒绝所有推送。

HttpClient的重载sendAsync可用于处理 push promise。先定义处理器:

private static PushPromiseHandler<String> pushPromiseHandler() { return (HttpRequest initiatingRequest, HttpRequest pushPromiseRequest, Function<HttpResponse.BodyHandler<String>, CompletableFuture<HttpResponse<String>>> acceptor) -> { acceptor.apply(BodyHandlers.ofString()) .thenAccept(resp -> { System.out.println("Pushed response: " + resp.uri() + ", headers: " + resp.headers()); }); System.out.println("Promise request: " + pushPromiseRequest.uri()); System.out.println("Promise request headers: " + pushPromiseRequest.headers()); }; }

再用sendAsync消费它:

httpClient.sendAsync(pageRequest, BodyHandlers.ofString(), pushPromiseHandler()) .thenAccept(pageResponse -> { System.out.println("Page response status code: " + pageResponse.statusCode()); System.out.println("Page response headers: " + pageResponse.headers()); String responseBody = pageResponse.body(); System.out.println(responseBody); }) .join();

9. 总结

本文探讨了 Java 11 中标准化后的HttpClientAPI:在保留易用性的同时,引入了 HTTP/2、异步、推送承诺、代理、重定向策略、认证器、Cookie 管理等现代化能力,让 Java 的 HTTP 编程更高效、更现代。

行业拓展

分享一个面向研发人群使用的前后端分离的低代码软件——JNPF。

基于 Java Boot/.Net Core双引擎,它适配国产化,支持主流数据库和操作系统,提供五十几种高频预制组件,内置了常用的后台管理系统使用场景和实用模版,通过简单的拖拉拽操作,开发者能够高效完成软件开发,提高开发效率,减少代码编写工作。

JNPF基于SpringBoot+Vue.js,提供了一个适合所有水平用户的低代码学习平台,无论是有经验的开发者还是编程新手,都可以在这里找到适合自己的学习路径。

此外,JNPF支持全源码交付,完全支持根据公司、项目需求、业务需求进行二次改造开发或内网部署,具备多角色门户、登录认证、组织管理、角色授权、表单设计、流程设计、页面配置、报表设计、门户配置、代码生成工具等开箱即用的在线服务。

http://www.jsqmd.com/news/379622/

相关文章:

  • P2698 [USACO12MAR] Flowerpot S
  • 中国移动(600941)价值投资深度研究报告 2026.2.13
  • 免费,在线pdf转jpg的链接。
  • 深入解析:Android平板备份到计算机
  • Winter Vacation 2026 - -Klsw
  • 小程序环境+基础页面
  • 三维点云处理技术和深度学习在点云处理中的应用-02:三维点云表征概述
  • 信息论与编码篇---N次拓展信道
  • 信息论与编码篇---积信道
  • 信息论与编码篇---可逆矩阵信道
  • Spark大数据处理:技术、应用与性能优化【1.2】
  • 有限元模型可视化:两套独立Python代码实现带载荷与纯几何对比
  • 6个提示词,能把混乱的剪辑变成专业策略
  • 26.2.12
  • 完整教程:leetcode算法(112.路径总和)
  • 使用Qwen Code的Skills能力重塑工作流 - yi
  • 大数据ETL工具比较:Sqoop vs Flume vs Kafka
  • Django 中间件
  • temperature定义与使用
  • Google API 教程
  • AI编程工具在高可用架构设计中的应用:从故障注入到灾备方案生成实战
  • 视频转换器HD Video Converter Factory 28.6 便携版
  • XML Schema 复合空元素
  • 2001-2024年上市公司媒体关注度数据+Stata代码
  • 必看!2026年琼海海鲜推荐榜单,探索高性价比家庭聚餐海鲜店与知名夜宵选择
  • 企业AI伦理准则制定中的跨部门协作:AI应用架构师的协调技巧
  • 6大方法教你禁止windows11自动更新,windows自动更新怎么关闭,有效阻止关闭win11更新
  • 把Kindle变成电子表!
  • Turnitin AI率爆表怎么办?揭秘网易有道“学术猹”的官方解决方案 - 品牌观察员小捷
  • Windows优化大师,Windows系统管理工具V9.53绿色优化版,附带实用工具箱,已调整功能优化,windows系统优化管理工具