在Spring WebFlux的响应式编程体系中,WebClient是执行HTTP请求的核心工具,而Mono和Flux作为Reactor的核心响应式类型,二者的结合使用需要遵循响应式流的执行规则,否则很容易出现请求不执行、结果不符合预期的问题。

基础调用逻辑
WebClient的调用方法本身返回的就是Mono或Flux类型,因此最基础的调用方式就是在响应式流中直接通过操作符衔接。需要注意的是,响应式流是懒执行的,只有最终被订阅时才会触发整个链路的操作。
比如在Mono中调用WebClient发起GET请求获取用户信息的示例:
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
public class WebClientDemo {
private final WebClient webClient;
public WebClientDemo(WebClient.Builder webClientBuilder) {
this.webClient = webClientBuilder.baseUrl("http://ipipp.com/api").build();
}
// 在Mono中调用WebClient的基础示例
public Mono<String> getUserInfo(Long userId) {
return webClient.get()
.uri("/users/{id}", userId)
.retrieve()
.bodyToMono(String.class);
}
}
在Flux中批量调用WebClient
当需要在Flux流中对每个元素发起WebClient请求时,需要选择合适的映射操作符,不同的操作符会有不同的执行特性。
操作符选择
- flatMap:异步执行,不保证顺序,适合不需要顺序且追求并发的场景,默认并发度为256,可以通过concurrency参数调整。
- concatMap:同步按顺序执行,保证元素的处理顺序和原Flux顺序一致,适合有顺序要求的场景。
- flatMapSequential:异步执行但会按原顺序输出结果,兼顾并发和顺序要求。
以下是使用concatMap在Flux中逐个调用WebClient的示例,假设需要批量查询多个用户的信息:
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
public class BatchWebClientDemo {
private final WebClient webClient;
public BatchWebClientDemo(WebClient.Builder webClientBuilder) {
this.webClient = webClientBuilder.baseUrl("http://ipipp.com/api").build();
}
// 批量查询用户信息,保证顺序执行
public Flux<String> batchGetUsers(Flux<Long> userIds) {
return userIds.concatMap(userId ->
webClient.get()
.uri("/users/{id}", userId)
.retrieve()
.bodyToMono(String.class)
);
}
}
异常处理方案
WebClient调用过程中可能会出现网络异常、接口返回错误状态码等情况,需要做好异常处理避免整个响应式流中断。
可以通过onStatus方法处理HTTP错误状态码,结合onErrorResume等操作符做降级处理:
import org.springframework.http.HttpStatus;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
public class WebClientErrorDemo {
private final WebClient webClient;
public WebClientErrorDemo(WebClient.Builder webClientBuilder) {
this.webClient = webClientBuilder.baseUrl("http://ipipp.com/api").build();
}
public Mono<String> getUserInfoWithErrorHandle(Long userId) {
return webClient.get()
.uri("/users/{id}", userId)
.retrieve()
// 处理4xx和5xx状态码
.onStatus(HttpStatus::isError, response ->
Mono.error(new RuntimeException("请求用户接口失败,状态码:" + response.statusCode()))
)
.bodyToMono(String.class)
// 异常时返回默认值
.onErrorResume(e -> Mono.just("默认用户信息"));
}
}
上下文传递注意事项
如果需要在WebClient请求中传递上下文信息,比如请求头中的认证信息,不能直接在外部设置后传入,因为响应式流中的上下文是通过Context传递的,需要在流内部获取上下文内容再设置到请求中。
以下是传递上下文认证信息的示例:
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
import reactor.util.context.Context;
public class WebClientContextDemo {
private final WebClient webClient;
public WebClientContextDemo(WebClient.Builder webClientBuilder) {
this.webClient = webClientBuilder.baseUrl("http://ipipp.com/api").build();
}
public Mono<String> getUserInfoWithContext(Long userId) {
return Mono.deferContextual(contextView -> {
String authToken = contextView.get("authToken");
return webClient.get()
.uri("/users/{id}", userId)
.header("Authorization", "Bearer " + authToken)
.retrieve()
.bodyToMono(String.class);
});
}
// 调用时设置上下文
public static void main(String[] args) {
WebClientContextDemo demo = new WebClientContextDemo(WebClient.builder());
demo.getUserInfoWithContext(1L)
.contextWrite(Context.of("authToken", "test_token"))
.subscribe(result -> System.out.println(result));
}
}
常见误区提醒
- 不要在响应式流中直接调用WebClient方法却不返回Mono/Flux,否则请求不会触发执行。
- 避免在flatMap等操作符中做阻塞操作,WebClient本身是响应式的,不需要额外用阻塞方式处理结果。
- 不要忽略WebClient的retrieve和exchange方法的区别,retrieve更简洁,exchange可以获取更完整的响应信息但需要手动处理响应体释放。
WebClientMonoFluxReactorSpring_WebFlux修改时间:2026-07-23 11:18:29