SpringBoot WebClient 全面解析
一、什么是 WebClient?
WebClient 是 Spring 5 引入的一个现代 HTTP 客户端,属于 Spring WebFlux 模块,用来发送 HTTP 请求(GET、POST、PUT、DELETE 等)。
它可以替代传统的 RestTemplate。(Home)
WebClient 它底层基于:
- Reactor
- Netty
- NIO
因此:
少量线程 处理大量请求
这也是它高并发能力强的原因。(Home)
官方文档:
二、 WebClient 能解决什么问题?
它主要用于:
- 调用第三方接口
- 微服务之间通信
- 下载文件
- 上传文件
- 调用 AI / OpenAPI 接口
- 高并发 HTTP 请求
- 异步并发调用多个接口
例如:
你的系统 ↓ WebClient ↓ 支付宝接口 / 微信接口 / 第三方系统
三、WebClient 和 RestTemplate 的区别
| 对比项 | WebClient | RestTemplate |
|---|---|---|
| 所属 | Spring WebFlux | Spring MVC |
| 是否异步 | 支持 | 默认同步阻塞 |
| 是否非阻塞 | 是 | 否 |
| 是否支持响应式 | 支持 Mono / Flux | 不支持 |
| 并发能力 | 高 | 一般 |
| 是否支持流式处理 | 支持 | 一般 |
| 推荐程度 | 新项目推荐 | 维护模式 |
| API 风格 | 链式 fluent API | 模板式 API |
Spring 官方已经说明:
RestTemplate进入 maintenance mode(维护模式)- 新项目更推荐
WebClient(Reddit)
四、WebClient 的核心优势
1. 非阻塞(Non-Blocking)
传统 RestTemplate:
线程发请求 ↓ 一直等待响应 ↓ 线程被占用
WebClient:
线程发请求 ↓ 不用等待 ↓ 线程去处理别的任务 ↓ 响应回来再通知
因此:
- 更省线程
- 更适合高并发
- 更适合微服务
支持同步调用
WebClient 虽然是响应式的,但你也能:
.block()
变成同步调用。
因此:
即使你不是响应式项目,也能使用 WebClient。
2. 支持异步
可以同时请求多个接口:
Mono<User> userMono = webClient.get()... Mono<Order> orderMono = webClient.get()...
最后组合:
Mono.zip(userMono, orderMono)
3. 链式 API 更现代
传统的 RestTemplate:
restTemplate.exchange(...)
而 WebClient:
webClient.get()
.uri("/user")
.retrieve()
.bodyToMono(User.class);
更像:
- Java8 Stream
- 函数式编程
- Reactor 响应式风格
五、WebClient 的核心对象
最重要的:
WebClient
它类似:
浏览器客户端
负责:
- 发请求
- 设置 header
- 设置 token
- 接收响应
- 下载文件
六、Mono 和 Flux 是什么?
WebClient 基于 Reactor。
两个核心类:
| 类型 | 含义 |
|---|---|
| Mono | 0~1 个结果 |
| Flux | 0~N 个结果 |
例如:
Mono<User> Flux<User>
表示:
Mono<User>表示未来会返回一个 User Flux<User>表示未来会返回多个 User
七、如何引入 WebClient?
Maven
Spring Boot 项目:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>即使你项目不是 WebFlux 项目,也能单独使用 WebClient。
八、WebClient 的基本创建方式
1. 创建 WebClient 最简单的使用方式
WebClient webClient = WebClient.create();
或者:
WebClient webClient = WebClient.create("https://api.example.com");
或者:
WebClient webClient = WebClient.builder()
.baseUrl("https://api.example.com")
.build();
2.Spring Bean 配置类方式(推荐)
配置类
@Configuration
public class WebClientConfig {
@Bean
public WebClient webClient() {
//配置超时和日志
HttpClient httpClient = HttpClient.create()
.responseTimeout(Duration.ofSeconds(10))
.wiretap(true);
return WebClient.builder()
//基本url域名
.baseUrl("https://api.example.com")
//默认请求头增加类型为json
.defaultHeader(HttpHeaders.CONTENT_TYPE,MediaType.APPLICATION_JSON_VALUE)
//默认请求头增加token
.defaultHeader(HttpHeaders.AUTHORIZATION, "Bearer abcdefg")
//超时配置和日志
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
}
}通常 token 是动态获取的,可以使用 filter,下面的示例使用 getToken() 动态获取 token。
Filter 示例
@Bean
public WebClient webClient() {
return WebClient.builder()
.filter((request, next) -> {
ClientRequest newRequest =
ClientRequest.from(request)
.header(HttpHeaders.AUTHORIZATION,"Bearer " + getToken())
.build();
return next.exchange(newRequest);})
.build();
}官方 builder 配置项包括:
- baseUrl
- defaultHeader
- filter
- codec
- timeout
- connector 等 (Spring 框架)
注入使用
@Autowired private WebClient webClient;
九、GET 带参数
请求
GET /user?page=1&size=10
代码
String result = webClient.get()
.uri(uriBuilder -> uriBuilder
.path("/user")
.queryParam("page", 1)
.queryParam("size", 10)
.build())
.headers(headers -> {
headers.setBearerAuth(token);
headers.add("appId", "1001");})
.retrieve()
.bodyToMono(String.class)
.block();
最终请求:
https://api.example.com/user?page=1&size=10
get()
表示 GET 请求:
webClient.get()
uri()
请求地址。
如果请求地址很简单可以这样写:
.uri("/user")
headers()
增加请求头,可以在配置类里配置默认的请求头
retrieve()
开始发送请求并获取响应:
.retrieve()
bodyToMono()
响应转对象:
.bodyToMono(String.class)
block()
阻塞等待结果:
.block();
注意:
WebClient 本身是异步的。
调用:
.block()
才会变成同步等待。
十、GET 返回对象
User 类
@Data
public class User {
private Long id;
private String name;
}调用
User user = webClient.get()
.uri("/user")
.retrieve()
.bodyToMono(User.class)
.block();
如果带参数和请求头:
User user = webClient.get()
.uri(uriBuilder -> uriBuilder
.path("/user")
.queryParam("page", 1)
.queryParam("size", 10)
.build())
.headers(headers -> {
headers.setBearerAuth(token);
headers.add("appId", "1001");})
.retrieve()
.bodyToMono(User.class)
.block();通过 bodyToMono(User.class) Spring 会自动 JSON 转 User 对象。
十一、POST 请求示例
请求
POST /user Content-Type: application/json
请求体:
{
"name":"张三",
"password":"123",
}DTO
@Data
public class UserReq {
private String name;
private String password;
}
POST 代码
UserReq req = new UserReq();
req.setName("张三");
req.setPassword("123");
String token = "Bearer xxxxxx";
String result = webClient.post()
.uri("/user")
//JSON 请求
.contentType(MediaType.APPLICATION_JSON)
//单次请求携带 Token. 可在配置类全局配置 Token
.header(HttpHeaders.AUTHORIZATION, token)
.bodyValue(req)
.retrieve()
.bodyToMono(String.class)
.block();如果是表单请求:
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
bodyValue() 是什么?
它表示:
把对象转为请求体 JSON
等价于:
{
"name":"张三"
}
十二、PUT 请求
webClient.put()
.uri("/user/1")
.bodyValue(req)
.retrieve()
.bodyToMono(String.class)
.block();
十三、DELETE 请求
webClient.delete()
.uri("/user/1")
.retrieve()
.bodyToMono(String.class)
.block();
十四、下载文件
这是企业里非常常见的场景。
下载文件为 byte[]
byte[] data = webClient.get()
.uri("https://example.com/test.pdf")
//如果需要携带token
.header(HttpHeaders.AUTHORIZATION,"Bearer xxxxxx")
.retrieve()
.bodyToMono(byte[].class)
.block();
保存本地文件
byte[] data = webClient.get()
.uri("https://example.com/test.pdf")
//如果需要携带token
.header(HttpHeaders.AUTHORIZATION,"Bearer xxxxxx")
.retrieve()
.bodyToMono(byte[].class)
.block();
Files.write(
Paths.get("D:/test.pdf"),
data
);
大文件下载(推荐流式)
如果文件很大, 有几百 MB 或者 几 GB,不推荐上面的 byte[] 下载,否则可能 OOM(内存溢出)
流式下载
Flux<DataBuffer> flux = webClient.get()
.uri("/download/file")
.retrieve()
.bodyToFlux(DataBuffer.class);
DataBufferUtils.write(
flux,
Paths.get("D:/big.zip"),
StandardOpenOption.CREATE
).block();或者:
webClient.get()
.uri("https://example.com/big.zip")
.retrieve()
.bodyToFlux(DataBuffer.class)
.map(DataBuffer::asByteBuffer)
.doOnNext(buffer -> {
// 写入文件
})
.blockLast();
十五、错误处理
普通写法
webClient.get()
.uri("/user")
.retrieve()
.bodyToMono(String.class)
如果:
404
500
会抛异常。
onStatus 状态码错误处理
String result = webClient.get()
.uri("/user")
.retrieve()
.onStatus(
HttpStatusCode::is4xxClientError,
response -> Mono.error(new RuntimeException("4xx异常"))
)
.onStatus(
HttpStatusCode::is5xxServerError,
response -> Mono.error(new RuntimeException("5xx异常"))
)
.bodyToMono(String.class)
.block();try-catch
try {
String result = webClient.get()
.uri("/test")
.retrieve()
.bodyToMono(String.class)
.block();
} catch (Exception e) {
e.printStackTrace();
}
十六、retrieve() 和 exchangeToMono() 区别
retrieve()(最常用)
适合:
- 普通接口调用
- 简洁开发
简单场景:
.retrieve() .bodyToMono(...)
exchangeToMono()
适合高级场景:
- 获取状态码
- 获取响应头、cookie
- 自定义响应处理
String result = webClient.get()
.uri("/user")
.exchangeToMono(response -> {
if (response.statusCode().is2xxSuccessful()) {
return response.bodyToMono(String.class);
}
return Mono.error(
new RuntimeException("请求失败")
);
})
.block();十七、 WebClient适合场景与不适合场景?
非常适合:
- 微服务
- 高并发
- API 网关
- 聚合接口
- AI 调用
- 并发请求多个服务
- SSE/流式响应
不适合的场景:
如果你的项目:
完全同步
低并发
传统 MVC
那么:
RestTemplate / RestClient
可能更简单。
社区里也有很多开发者提到:
- WebFlux 会增加复杂度
- Mono / Flux 学习成本较高 (Reddit)
十八、WebClient 学习路线
建议按这个顺序学习:
- WebClient 基础 API
- Mono / Flux
- Reactor
- 异步编程
- 响应式编程
- Netty
- 背压(BackPressure)
十九、最常用写法总结
1.GET
webClient.get()
2.POST
webClient.post()
3.设置 header
.header()
4.设置 body
.bodyValue()
5.获取响应
.retrieve() .bodyToMono()
6.阻塞等待
.block()
二十、完整实战示例
封装 HttpClientService
@Service
public class HttpClientService {
private final WebClient webClient;
public HttpClientService(WebClient.Builder builder) {
this.webClient = builder
.baseUrl("https://api.example.com")
.defaultHeader(HttpHeaders.CONTENT_TYPE,
MediaType.APPLICATION_JSON_VALUE)
.build();
}
// GET
public String getUser() {
return webClient.get()
.uri("/user/1")
.retrieve()
.bodyToMono(String.class)
.block();
}
// POST
public String login(LoginRequest request) {
return webClient.post()
.uri("/login")
.bodyValue(request)
.retrieve()
.bodyToMono(String.class)
.block();
}
// token请求
public String getWithToken(String token) {
return webClient.get()
.uri("/user/info")
.header(HttpHeaders.AUTHORIZATION,
"Bearer " + token)
.retrieve()
.bodyToMono(String.class)
.block();
}
}二十一、最后总结
WebClient 本质上:
Spring 官方现代 HTTP 客户端
它最大的特点:
- 非阻塞
- 响应式
- 高并发
- 异步
- 链式 API
企业中现在越来越多:
微服务 + WebClient
的组合。
但它的核心难点其实不是 WebClient 本身,而是:
Mono / Flux / Reactor
到此这篇关于SpringBoot WebClient 全面解析的文章就介绍到这了,更多相关SpringBoot WebClient 内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
SpringBoot+Vue简单前后端分离项目的增删改查方式
文章主要介绍了使用SpringBoot进行前后端开发的过程,包括SpringBoot项目的搭建、配置、后端业务开发、前端页面搭建等步骤,并详细阐述了数据增删改查的实现方法2026-04-04
JAVA WSIMPORT生成WEBSERVICE客户端401认证过程图解
这篇文章主要介绍了JAVA WSIMPORT生成WEBSERVICE客户端401认证过程图解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下2020-10-10
SpringBoot整合Spring Data JPA的详细方法
JPA全称为Java Persistence API(Java持久层API),是一个基于ORM的标准规范,在这个规范中,JPA只定义标准规则,不提供实现,本文重点给大家介绍SpringBoot整合Spring Data JPA的相关知识,感兴趣的朋友一起看看吧2022-02-02


最新评论