一、概述

Java 11引入了一个全新的标准HTTP客户端API,位于java.net.http包中,旨在取代自Java早期就存在的HttpURLConnection类。该API此前在Java 9中以孵化器模块形式出现,经过Java 10的迭代更新,最终在Java 11中正式标准化。新的HTTP客户端提供了一种更现代化、更易用的方式来处理HTTP通信,支持HTTP/2和WebSocket,并同时提供同步与异步两种编程模型。

与传统的HttpURLConnection相比,java.net.http.HttpClient具备以下显著优势:

特性 说明
无需第三方依赖 属于Java标准库的一部分,开箱即用
HTTP/2原生支持 支持多路复用、头部压缩等性能优化特性
异步非阻塞 基于CompletableFuture,可高效处理高并发场景
构建器模式 采用流式API,配置和构建过程简洁直观
内置WebSocket客户端 无需额外依赖即可实现WebSocket通信

在Java 11之前,开发者通常使用HttpURLConnection(功能过于底层)或引入Apache HttpClient等第三方库(增加依赖管理负担)来处理HTTP请求。新的HTTP Client API弥补了标准库在这一领域的长期空白。

二、核心组件:HttpClient、HttpRequest与HttpResponse

HTTP Client API围绕三个核心类设计,职责划分清晰:

  • HttpClient:负责管理客户端层面的配置(如协议版本、重定向策略、代理、认证器等),并实际执行请求的发送。HttpClient实例一旦创建即不可变,可重复用于发送多个请求。
  • HttpRequest:使用构建器模式构建,封装单个HTTP请求的全部信息,包括URI、HTTP方法、请求头、请求体等。HttpRequest同样是不可变的,可多次发送。
  • HttpResponse:封装服务器返回的响应,包含状态码、响应头和响应体。响应体可以通过BodyHandler以字符串、字节数组、文件等多种方式消费。

这种清晰的三层分离使得HTTP通信的各个关注点得以解耦:客户端管理连接和策略,请求描述具体调用,响应承载返回数据。

三、创建和配置HttpClient

3.1 基本创建方式

HttpClient提供了两种创建实例的方式:

  • HttpClient.newHttpClient():返回使用默认配置的HttpClient实例,适用于大多数基本场景。
  • HttpClient.newBuilder():返回构建器,允许对客户端进行详细配置。

3.2 常用配置项

以下是一个配置较为完整的HttpClient构建示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.johnson.example.httpclient;

import java.net.http.HttpClient;
import java.net.http.HttpClient.Redirect;
import java.net.http.HttpClient.Version;
import java.net.ProxySelector;
import java.time.Duration;

/**
*
* @author johnson lin
* @date 2026/4/13 01:23
*/
public class HttpClientConfigurationExample {
public static void main(String[] args) {
HttpClient client = HttpClient.newBuilder()
.version(Version.HTTP_2) // 首选HTTP/2,协商失败时回退到HTTP/1.1
.followRedirects(Redirect.NORMAL) // 自动跟随重定向
.connectTimeout(Duration.ofSeconds(10)) // 设置连接超时时间
.proxy(ProxySelector.getDefault()) // 设置代理选择器
.build();
}
}

主要配置项说明:

配置方法 作用
version(Version) 设置首选HTTP协议版本。HTTP_2会优先尝试HTTP/2,协商失败则回退至HTTP/1.1
followRedirects(Redirect) 配置重定向策略。Redirect.NORMAL表示对除HTTPS到HTTP之外的重定向进行自动跟随
connectTimeout(Duration) 设置等待与服务器建立连接的最长时间
proxy(ProxySelector) 配置代理服务器

HttpClient实例是不可变的,所有配置在构建后即固定,因此该实例可以安全地在多个线程间共享,并且内部自动维护连接池,以提升性能。

四、构建和发送请求

4.1 构建HttpRequest

HttpRequest同样采用构建器模式创建。以下是一个GET请求的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.johnson.example.httpclient;

import java.net.URI;
import java.net.http.HttpRequest;
import java.time.Duration;

/**
*
* @author johnson lin
* @date 2026/4/13 01:38
*/
public class HttpRequestConfigurationExample {
public static void main(String[] args) {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/users"))
.timeout(Duration.ofSeconds(30)) // 设置整个请求的超时时间
.header("Accept", "application/json") // 添加自定义请求头
.GET() // 指定GET方法(默认)
.build();
}
}

4.2 发送请求并处理响应

发送请求主要通过HttpClient的两个核心方法:

  • send(HttpRequest, BodyHandler):同步方式。调用线程将被阻塞,直到收到完整响应。
  • sendAsync(HttpRequest, BodyHandler):异步方式。立即返回CompletableFuture<HttpResponse>,响应到达时自动完成该Future。

两个方法均需要传入一个BodyHandler参数,用于指定如何解析响应体。

4.3 同步请求示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.johnson.example.httpclient;

import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

/**
*
* @author johnson lin
* @date 2026/4/13 01:43
*/
public class HttpRequestSyncExample {
public static void main(String[] args) {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://jsonplaceholder.typicode.com/posts/1"))
.build();

try {
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println("状态码: " + response.statusCode());
System.out.println("响应体: " + response.body());
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
}

4.4 异步请求示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package com.johnson.example.httpclient;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

/**
*
* @author johnson lin
* @date 2026/4/13 01:46
*/
public class HttpRequestAsyncExample {
public static void main(String[] args) {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://jsonplaceholder.typicode.com/posts/1"))
.build();

client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenAccept(response -> {
System.out.println("状态码: " + response.statusCode());
System.out.println("响应体: " + response.body());
})
.exceptionally(e -> {
System.err.println("请求失败: " + e.getMessage());
return null;
});
// .join();
// 注意:异步操作不会阻塞主线程,如需等待完成可调用join()
}
}

五、BodyHandler与BodyPublisher详解

5.1 响应体处理(BodyHandler)

HttpResponse.BodyHandler用于将响应体转换为特定类型。BodyHandlers工具类提供了多种预定义的处理器:

方法 返回类型 适用场景
ofString() String 将响应体读取为字符串
ofBytes() byte[] 将响应体读取为字节数组
ofFile(Path) Path 将响应体直接写入文件
ofInputStream() InputStream 以流式方式处理响应体,适合大文件下载
ofLines() Stream<String> 按行流式读取响应体,适合处理大文本数据
discarding() Void 忽略响应体,仅关注状态码和响应头

5.2 请求体发布(BodyPublisher)

发送POST、PUT等需要携带请求体的请求时,使用HttpRequest.BodyPublisher来提供请求体内容。BodyPublishers工具类提供了多种预定义的发布器:

1
2
3
4
5
6
// POST请求示例
HttpRequest postRequest = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/users"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString("{\"name\":\"张三\"}"))
.build();
方法 适用场景
ofString(String) 发送字符串格式的请求体(如JSON、XML、纯文本)
ofBytes(byte[]) 发送字节数组
ofFile(Path) 从文件读取内容作为请求体
ofInputStream(Supplier<InputStream>) 从输入流读取请求体
noBody() 发送无请求体的请求(GET、DELETE默认使用)

六、同步与异步编程模式

6.1 模式对比

维度 同步(send) 异步(sendAsync)
线程行为 调用线程阻塞,等待响应返回 调用线程立即返回,不阻塞
返回值 HttpResponse<T> CompletableFuture<HttpResponse<T>>
适用场景 批量处理、简单请求、脚本类任务 高并发、微服务间调用、UI响应式编程
错误处理 使用try-catch捕获异常 通过exceptionally()handle()处理

6.2 异步请求的并发组合

CompletableFuture提供了丰富的组合能力,可以轻松实现多个异步请求的并发执行或串行编排:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package com.johnson.example.httpclient;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

/**
*
* @author johnson lin
* @date 2026/4/13 02:23
*/
public class HttpRequestConcurrentExample {
public static void main(String[] args) throws ExecutionException, InterruptedException {
HttpClient client = HttpClient.newHttpClient();

// 并发发送多个请求
HttpRequest request1 = HttpRequest.newBuilder().uri(URI.create("https://api1.com/data")).build();
HttpRequest request2 = HttpRequest.newBuilder().uri(URI.create("https://api2.com/info")).build();

CompletableFuture<HttpResponse<String>> future1 = client.sendAsync(request1, HttpResponse.BodyHandlers.ofString());
CompletableFuture<HttpResponse<String>> future2 = client.sendAsync(request2, HttpResponse.BodyHandlers.ofString());

// 等待所有请求完成
CompletableFuture.allOf(future1, future2).join();

// 分别获取结果
String data1 = future1.get().body();
String data2 = future2.get().body();
}
}

七、HTTP/2特性

从Java 11开始,HttpClient默认支持HTTP/2协议。当服务器和TLS层通过ALPN(Application-Layer Protocol Negotiation)协商支持HTTP/2时,客户端将利用HTTP/2的多路复用能力——在单个TCP连接上同时传输多个请求,这显著降低了微服务架构或高并发场景中的网络延迟。

值得注意的是,若要实际使用HTTP/2 over TLS,服务器端也需要相应配置。例如,Tomcat 9.0.1及以上版本默认启用HTTP/2,且需要配置TLS支持。若服务器不支持HTTP/2,客户端会自动回退到HTTP/1.1。

八、WebSocket客户端支持

除了HTTP请求处理之外,HttpClient还内置了WebSocket客户端支持。通过HttpClient.newWebSocketBuilder()方法可以创建WebSocket连接:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.johnson.example.httpclient;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.WebSocket;
import java.util.concurrent.CompletionStage;

/**
*
* @author johnson lin
* @date 2026/4/13 03:18
*/
public class WebSocketExample {
public static void main(String[] args) {
HttpClient client = HttpClient.newHttpClient();

WebSocket websocket = client.newWebSocketBuilder()
.buildAsync(URI.create("ws://example.com/chat"), new WebSocket.Listener() {
@Override
public CompletionStage<?> onText(WebSocket webSocket, CharSequence data, boolean last) {
System.out.println("收到消息: " + data);
webSocket.request(1); // 请求接收下一条消息
return null;
}

@Override
public void onOpen(WebSocket webSocket) {
System.out.println("连接已打开");
webSocket.sendText("Hello", true);
}
})
.join();
}
}

WebSocket支持使得实现实时双向通信(如聊天应用、实时仪表盘、事件流等)无需引入第三方依赖,即可与Java标准库无缝集成。

九、小结

JDK 11引入的标准化HTTP Client API为Java开发者带来了久违的现代化HTTP通信体验。快速回顾其核心特性:

特性 说明
无需第三方依赖 属于Java标准库,开箱即用
HTTP/2原生支持 自动协商与回退,多路复用提升性能
同步与异步双模式 send()用于阻塞场景,sendAsync()配合CompletableFuture应对高并发
流畅的构建器API HttpClientHttpRequest均采用构建器模式,配置直观
灵活的响应/请求体处理 BodyHandlersBodyPublishers提供多种内置处理器
内置WebSocket客户端 newWebSocketBuilder()支持全双工实时通信

如果你的项目已经升级到JDK 11或更高版本,建议在需要发送HTTP请求的场景中优先使用java.net.http.HttpClient,让代码更加简洁、健壮且易于维护。

如果需要进一步了解本文涉及的各类API的更多细节,可以参考 Oracle官方文档 中的相关内容。