Spring响应式开发中WebClient未按预期发起请求获取数据
问题分析与解决方案
核心问题1:控制器未正确订阅反应式流
你的控制器代码中,Mono.just(ResponseEntity.ok(service.get(value))) 将 Mono<SomeClass> 直接作为ResponseEntity的body返回,这会导致两个关键问题:
- 反应式流是懒加载机制,只有被订阅时才会执行实际逻辑,这里的内部
Mono没有被订阅,所以WebClient的GET请求根本不会发起。 - 返回的是
Mono对象的序列化结果(比如"scanAvailable": true),而非预期的SomeClass数据结构。
修复后的控制器代码:
@PostMapping("/follow/{value}") public Mono<ResponseEntity<?>> someFunction(@PathVariable int value) { return service.get(value) // GET请求成功时,将结果包装为200响应 .map(ResponseEntity::ok) // 处理POST返回的400参数错误 .onErrorResume(SomeException2.class, e -> Mono.just(ResponseEntity.badRequest().body(e.getMessage()))) // 处理重试相关的错误状态 .onErrorResume(SomeException1.class, e -> Mono.just(ResponseEntity.status(e.getStatusCode()).body(e.getMessage()))); }
修改后Spring会自动订阅service.get(value)返回的Mono,触发WebClient请求,同时正确处理不同错误场景的响应格式。
核心问题2:WebClient可能未配置正确的BaseUrl
如果你的WebClient实例没有配置baseUrl,uri("/" + value)会默认指向当前应用的路径,而非外部API地址http://api.examplepage.com/{value},导致请求发错地址,自然无法触发预期的状态处理逻辑。
确保WebClient配置了BaseUrl:
@Bean public WebClient webClient() { return WebClient.builder() .baseUrl("http://api.examplepage.com") .build(); }
其他逻辑优化与调试建议
- 404处理逻辑验证:当前404时调用
requestGeneration后抛出SomeException1触发重试GET的逻辑符合预期,可添加日志确认POST请求是否执行:
private Mono<Void> requestGeneration(int value) { return webClient.post() .uri("/" + value) .retrieve() .onRawStatus(HttpStatus.BAD_REQUEST::equals, clientResponse -> Mono.error(new SomeException2("参数错误", clientResponse.rawStatusCode()))) .bodyToMono(Void.class) .doOnSuccess(v -> System.out.println("POST请求成功,value: " + value)) .doOnError(e -> System.out.println("POST请求失败,value: " + value + ",错误信息: " + e.getMessage())); }
- 重试策略调整:若要覆盖5-300秒的退避范围,可调整重试配置:
.retryWhen(Retry.backoff(10, Duration.ofSeconds(5)) .maxBackoff(Duration.ofSeconds(300)) .filter(throwable -> throwable instanceof SomeException1))
这样初始间隔5秒,最大退避到300秒,最多重试10次,更贴合你的需求。
- 调试辅助钩子:在
get方法中添加日志,确认流的执行状态:
public Mono<SomeClass> get(int value) { return webClient.get() .uri("/" + value) .retrieve() .onRawStatus(HttpStatus.CONFLICT::equals, clientResponse -> Mono.error(new SomeException1("资源冲突", clientResponse.rawStatusCode()))) .onRawStatus(HttpStatus.NOT_FOUND::equals, clientResponse -> { return requestGeneration(value) .flatMap(res -> Mono.error(new SomeException1("POST后重试GET", clientResponse.rawStatusCode()))); }) .bodyToMono(SomeClass.class) .doOnSubscribe(s -> System.out.println("GET请求已订阅,value: " + value)) .doOnNext(data -> System.out.println("GET请求成功,返回数据: " + data)) .doOnError(e -> System.out.println("GET请求失败,错误信息: " + e.getMessage())) .retryWhen(Retry.backoff(10, Duration.ofSeconds(5)) .maxBackoff(Duration.ofSeconds(300)) .filter(throwable -> throwable instanceof SomeException1)); }
内容的提问来源于stack exchange,提问作者karczi
相关产品推荐
相关产品推荐

