Mono switchIfEmpty重复执行问题:多参数API调用逻辑异常排查
问题分析与解决方案
核心问题
你的代码里switchIfEmpty看似总是执行,主要有两个关键原因:
checkResponse未正确将“无效响应”转为Mono.empty():当前实现只要API返回2xx状态码,就会返回包含响应字符串的Mono,哪怕内容是业务上的无效值(比如空字符串、错误标识),这时候switchIfEmpty不会触发;但如果API调用失败(非2xx),会直接抛出异常,也不会进入switchIfEmpty逻辑。switchIfEmpty参数未延迟执行:虽然WebClient请求是懒订阅,但直接传入checkResponse(stringArg2)会提前创建Mono实例(虽然请求不会立即发起),如果你的调试日志显示这个方法被调用,会误以为请求已执行,但实际只有上游Mono为空时才会订阅第二个Mono。
修正步骤
1. 重构checkResponse,统一“无效”场景为Mono.empty()
先把API调用失败、响应内容无效这两种“无效”场景,都转为Mono.empty(),确保只有有效响应才会传递到下游:
public Mono<String> checkResponse(String s) { return webClient.post() .uri(URI) .body(BodyInserters.fromValue(s)) .retrieve() .bodyToMono(String.class) // 自定义业务规则:判断响应是否有效,无效则转为empty .filter(response -> isValid(response)) // 捕获API调用异常(比如4xx/5xx),转为empty .onErrorResume(ex -> Mono.empty()); } // 替换为你的业务有效响应判断逻辑 private boolean isValid(String response) { return response != null && !response.trim().isEmpty() && !"INVALID".equals(response); }
2. 用Mono.defer()延迟第二个调用的创建
确保只有第一个调用返回empty时,才会创建并执行第二个checkResponse:
checkResponse(stringArg1) .switchIfEmpty(Mono.defer(() -> checkResponse(stringArg2))) .flatMapMany(...) .flatMap(...);
逻辑说明
- 第一个
checkResponse(stringArg1)如果返回有效响应,直接进入后续的flatMapMany/flatMap逻辑,第二个调用不会被执行。 - 如果第一个调用返回
Mono.empty()(无论响应无效还是API失败),Mono.defer()才会触发,创建并执行第二个checkResponse(stringArg2)。 - 如果第二个调用也返回
Mono.empty(),整个链路会返回Mono.empty(),终止后续调用。
内容的提问来源于stack exchange,提问作者Lucho82
相关产品推荐
相关产品推荐

