目录
- 一、什么是 WebClient?
- 二、 WebClient 能解决什么问题?
- 三、WebClient 和 RestTemplate 的区别
- 四、WebClient 的核心优势
- 1. 非阻塞(Non-Blocking)
- 2. 支持异步
- 3. 链式 API 更现代
- 五、WebClient 的核心对象
- 六、Mono 和 Flux 是什么?
- 七、如何引入 WebClient?
- Maven
- 八、WebClient 的基本创建方式
- 1. 创建 WebClient 最简单的使用方式
- 2.Spring Bean 配置类方式(推荐)
- 九、GET 带参数
- 请求
- 代码
- 代码解析
- get()
- uri()
- headers()
- retrieve()
- bodyToMono()
- block()
- 十、GET 返回对象
- User 类
- 调用
- 十一、POST 请求示例
- 请求
- DTO
- POST 代码
- bodyValue() 是什么?
- 十二、PUT 请求
- 十三、DELETE 请求
- 十四、下载文件
- 下载文件为 byte[]
- 保存本地文件
- 大文件下载(推荐流式)
- 十五、错误处理
- 普通写法
- onStatus 状态码错误处理
- try-catch
- 十六、retrieve() 和 exchangeToMono() 区别
- retrieve()(最常用)
- exchangeToMono()
- 十七、 WebClient适合场景与不适合场景?
- 十八、WebClient 学习路线
- 十九、最常用写法总结
- 1.GET
- 2.POST
- 3.设置 header
- 4.设置 body
- 5.获取响应
- 6.阻塞等待
- 二十、完整实战示例
- 二十一、最后总结
一、什么是 WebClient?
WebClient是 Spring 5 引入的一个现代 HTTP 客户端,属于 Spring WebFlux 模块,用来发送 HTTP 请求(GET、POST、PUT、DELETE 等)。
它可以替代传统的RestTemplate。(Home)
WebClient 它底层基于:
- Reactor
- Netty
- NIO
因此:
少量线程 处理大量请求这也是它高并发能力强的原因。(Home)
官方文档:
- Spring WebClient 官方文档
- Spring WebFlux 官方文档
二、 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 最简单的使用方式
WebClientwebClient=WebClient.create();或者:
WebClientwebClient=WebClient.create("https://api.example.com");或者:
WebClientwebClient=WebClient.builder().baseUrl("https://api.example.com").build();2.Spring Bean 配置类方式(推荐)
配置类
@ConfigurationpublicclassWebClientConfig{@BeanpublicWebClientwebClient(){//配置超时和日志HttpClienthttpClient=HttpClient.create().responseTimeout(Duration.ofSeconds(10)).wiretap(true);returnWebClient.builder()//基本url域名.baseUrl("https://api.example.com")//默认请求头增加类型为json.defaultHeader(HttpHeaders.CONTENT_TYPE,MediaType.APPLICATION_JSON_VALUE)//默认请求头增加token.defaultHeader(HttpHeaders.AUTHORIZATION,"Bearer abcdefg")//超时配置和日志.clientConnector(newReactorClientHttpConnector(httpClient)).build();}}通常 token 是动态获取的,可以使用 filter,下面的示例使用 getToken() 动态获取 token。
Filter 示例
@BeanpublicWebClientwebClient(){returnWebClient.builder().filter((request,next)->{ClientRequestnewRequest=ClientRequest.from(request).header(HttpHeaders.AUTHORIZATION,"Bearer "+getToken()).build();returnnext.exchange(newRequest);}).build();}官方 builder 配置项包括:
- baseUrl
- defaultHeader
- filter
- codec
- timeout
- connector 等 (Spring 框架)
注入使用
@AutowiredprivateWebClientwebClient;九、GET 带参数
请求
GET /user?page=1&size=10代码
Stringresult=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 类
@DatapublicclassUser{privateLongid;privateStringname;}调用
Useruser=webClient.get().uri("/user").retrieve().bodyToMono(User.class).block();如果带参数和请求头:
Useruser=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
@DatapublicclassUserReq{privateStringname;privateStringpassword;}POST 代码
UserReqreq=newUserReq();req.setName("张三");req.setPassword("123");Stringtoken="Bearer xxxxxx";Stringresult=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 状态码错误处理
Stringresult=webClient.get().uri("/user").retrieve().onStatus(HttpStatusCode::is4xxClientError,response->Mono.error(newRuntimeException("4xx异常"))).onStatus(HttpStatusCode::is5xxServerError,response->Mono.error(newRuntimeException("5xx异常"))).bodyToMono(String.class).block();try-catch
try{Stringresult=webClient.get().uri("/test").retrieve().bodyToMono(String.class).block();}catch(Exceptione){e.printStackTrace();}十六、retrieve() 和 exchangeToMono() 区别
retrieve()(最常用)
适合:
- 普通接口调用
- 简洁开发
简单场景:
.retrieve().bodyToMono(...)exchangeToMono()
适合高级场景:
- 获取状态码
- 获取响应头、cookie
- 自定义响应处理
Stringresult=webClient.get().uri("/user").exchangeToMono(response->{if(response.statusCode().is2xxSuccessful()){returnresponse.bodyToMono(String.class);}returnMono.error(newRuntimeException("请求失败"));}).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
@ServicepublicclassHttpClientService{privatefinalWebClientwebClient;publicHttpClientService(WebClient.Builderbuilder){this.webClient=builder.baseUrl("https://api.example.com").defaultHeader(HttpHeaders.CONTENT_TYPE,MediaType.APPLICATION_JSON_VALUE).build();}// GETpublicStringgetUser(){returnwebClient.get().uri("/user/1").retrieve().bodyToMono(String.class).block();}// POSTpublicStringlogin(LoginRequestrequest){returnwebClient.post().uri("/login").bodyValue(request).retrieve().bodyToMono(String.class).block();}// token请求publicStringgetWithToken(Stringtoken){returnwebClient.get().uri("/user/info").header(HttpHeaders.AUTHORIZATION,"Bearer "+token).retrieve().bodyToMono(String.class).block();}}二十一、最后总结
WebClient 本质上:
Spring 官方现代 HTTP 客户端它最大的特点:
- 非阻塞
- 响应式
- 高并发
- 异步
- 链式 API
企业中现在越来越多:
微服务 + WebClient的组合。
但它的核心难点其实不是 WebClient 本身,而是:
Mono / Flux / Reactor