Spring webflux之WebClient
WebClient 详解

WebClient 是 Spring WebFlux 提供的非阻塞、响应式 HTTP 客户端,用于替代传统的 RestTemplate(已过时),支持异步、流式请求处理,非常适合微服务间通信或调用外部 API。以下是其核心 API 和使用方式的详细讲解:
一、核心概念与创建方式
WebClient 基于响应式编程模型,所有操作返回 Mono 或 Flux,支持链式调用。
1. 创建 WebClient
// 方式1:默认创建(无基础URL)
WebClient webClient = WebClient.create();
// 方式2:指定基础URL(适合调用同一服务的多个接口)
WebClient webClient = WebClient.create("https://api.example.com");
// 方式3:自定义配置(超时、拦截器等)
WebClient webClient = WebClient.builder()
.baseUrl("https://api.example.com")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) // 默认请求头
.clientConnector(new ReactorClientHttpConnector(
HttpClient.create()
.responseTimeout(Duration.ofSeconds(10)) // 响应超时
))
.filter((request, next) -> { // 请求拦截器(如添加Token)
ClientRequest filtered = ClientRequest.from(request)
.header("Authorization", "Bearer token")
.build();
return next.exchange(filtered);
})
.build();
二、核心 API 与请求流程
WebClient 的使用遵循三步流程:
创建请求(method + URL)→ 配置请求(头、参数、体)→ 发送请求并处理响应
1. 定义 HTTP 方法与 URL(第一步)
通过 method(HTTP_METHOD) 或快捷方法(get()/post() 等)指定请求类型,结合 uri() 设置 URL:
// 基础用法
webClient.get() // HTTP方法:GET
.uri("/users") // URL路径(基于baseUrl)
// 带路径参数
webClient.get()
.uri("/users/{id}", 1L) // 路径参数:/users/1
// 带查询参数
webClient.get()
.uri(uriBuilder -> uriBuilder
.path("/users")
.queryParam("name", "Alice")
.queryParam("page", 1)
.build()) // 结果:/users?name=Alice&page=1
2. 配置请求(第二步)
通过链式方法配置请求头、请求体、Cookie 等:
| 方法 | 作用 | 示例 |
|---|---|---|
header(name, value) | 设置单个请求头 | .header("Accept", "application/json") |
headers(consumer) | 批量设置请求头 | .headers(headers -> headers.setBasicAuth("user", "pass")) |
body(...) | 设置请求体(支持 Mono/Flux) | .body(Mono.just(user), User.class) |
bodyValue(value) | 简化版设置请求体(直接传对象) | .bodyValue(user) |
cookie(name, value) | 设置 Cookie | .cookie("sessionId", "xxx") |
attribute(key, val) | 设置自定义属性(供拦截器使用) | .attribute("traceId", "123") |
3. 发送请求并处理响应(第三步)
通过以下方法发送请求,返回响应式结果(Mono/Flux):
| 方法 | 作用 | 适用场景 |
|---|---|---|
retrieve() | 简化的响应处理(自动提取响应体) | 大多数场景,直接获取响应体 |
exchangeToMono() | 完整响应处理(可获取状态码、头、体) | 需要处理状态码(如 404/500)或响应头 |
exchangeToFlux() | 流式响应处理(适合 SSE 等流式数据) | 处理服务器推送的流式响应(如 text/event-stream) |
三、响应处理详解
1. 简化处理:retrieve()
自动提取响应体,适合只关注数据的场景,错误状态码(如 4xx/5xx)会触发 onError:
// 1. 获取单个对象(Mono)
Mono<User> userMono = webClient.get()
.uri("/users/1")
.retrieve()
.bodyToMono(User.class); // 响应体转为 User 对象
// 2. 获取列表(Flux)
Flux<User> userFlux = webClient.get()
.uri("/users")
.retrieve()
.bodyToFlux(User.class); // 响应体转为 User 流
// 3. 处理错误状态码
Mono<User> userWithErrorHandler = webClient.get()
.uri("/users/999")
.retrieve()
.onStatus(HttpStatus::is4xxClientError, response -> { // 处理 4xx 错误
return Mono.error(new RuntimeException("用户不存在"));
})
.onStatus(HttpStatus::is5xxServerError, response -> { // 处理 5xx 错误
return Mono.error(new RuntimeException("服务器错误"));
})
.bodyToMono(User.class);
2. 完整处理:exchangeToMono()/exchangeToFlux()
获取完整的 ClientResponse(包含状态码、响应头、响应体),适合复杂场景:
// 处理完整响应(状态码 + 响应体)
Mono<Result<User>> resultMono = webClient.get()
.uri("/users/1")
.exchangeToMono(response -> {
// 获取状态码
HttpStatus status = response.statusCode();
// 根据状态码处理
if (status.is2xxSuccessful()) {
// 成功:解析响应体
return response.bodyToMono(User.class)
.map(user -> new Result<>(true, user, null));
} else {
// 失败:返回错误信息
return response.bodyToMono(String.class)
.map(error -> new Result<>(false, null, error));
}
});
3. 处理流式响应(如 SSE)
对于服务器推送的流式数据(text/event-stream),用 exchangeToFlux() 或 retrieve() 配合 bodyToFlux():
// 接收 SSE 流式数据
Flux<Event> eventFlux = webClient.get()
.uri("/stream/events")
.accept(MediaType.TEXT_EVENT_STREAM) // 声明接收流式数据
.retrieve()
.bodyToFlux(Event.class); // 逐个解析流中的事件
// 订阅并处理每个事件
eventFlux.subscribe(
event -> System.out.println("收到事件:" + event),
error -> System.err.println("错误:" + error),
() -> System.out.println("流结束")
);
四、常用场景示例
1. POST 请求(提交数据)
// 提交单个对象并获取响应
Mono<User> createdUser = webClient.post()
.uri("/users")
.contentType(MediaType.APPLICATION_JSON) // 设置请求体类型
.bodyValue(new User(null, "Bob")) // 请求体:User对象(自动转为JSON)
.retrieve()
.bodyToMono(User.class); // 响应体:创建的User(含ID)
2. PUT 请求(更新数据)
Mono<Void> updateResult = webClient.put()
.uri("/users/{id}", 1L)
.bodyValue(new User(1L, "Alice Updated"))
.retrieve()
.bodyToMono(Void.class); // 无响应体,用 Void
3. DELETE 请求
Mono<Void> deleteResult = webClient.delete()
.uri("/users/{id}", 1L)
.retrieve()
.bodyToMono(Void.class);
五、高级特性
1. 超时设置
通过 HttpClient 配置全局超时,或为单个请求设置超时:
// 单个请求超时
Mono<User> userWithTimeout = webClient.get()
.uri("/users/1")
.httpRequest(httpRequest -> {
httpRequest.timeout(Duration.ofSeconds(5)); // 该请求超时5秒
})
.retrieve()
.bodyToMono(User.class);
2. 文件上传 / 下载
// 下载文件(保存到本地)
webClient.get()
.uri("/files/report.pdf")
.retrieve()
.bodyToFlux(DataBuffer.class) // 以数据流接收文件
.map(dataBuffer -> {
// 写入本地文件
Files.write(Paths.get("report.pdf"), DataBufferUtils.extract(dataBuffer));
DataBufferUtils.release(dataBuffer); // 释放资源
return true;
})
.blockLast(); // 阻塞等待完成(仅示例,实际应避免阻塞)
六、与 RestTemplate 对比
| 特性 | WebClient(WebFlux) | RestTemplate(Spring MVC) |
|---|---|---|
| 编程模型 | 响应式(异步非阻塞) | 命令式(同步阻塞) |
| 性能 | 高(适合高并发、IO 密集场景) | 一般(阻塞 IO,线程开销大) |
| 流式处理 | 支持(Flux 处理数据流) | 不支持(需一次性加载全部数据) |
| 背压支持 | 支持(根据下游处理能力调节上游速度) | 不支持 |
| 扩展性 | 好(可集成响应式生态如 Kafka) | 有限 |
总结
WebClient 是 Spring 响应式生态中的核心 HTTP 客户端,其 API 设计遵循链式调用,通过 创建请求→配置请求→处理响应 三步流程完成操作。关键是根据场景选择 retrieve()(简化)或 exchangeToMono()(完整控制),并利用 Mono/Flux 处理异步结果。相比传统的 RestTemplate,它更适合现代微服务架构中的高并发场景。
更多推荐


所有评论(0)