如何在Project Reactor中捕获WebClient请求的404异常?
问题原因与解决办法
为什么subscribe的错误处理没生效?
核心问题是异步操作未被等待。JUnit测试方法会在执行完当前线程代码后直接结束,而WebClient的请求是异步非阻塞的,subscribe注册的回调逻辑还没来得及执行,测试就已经终止了,所以你看不到任何输出。而block()是阻塞式调用,会强制等待异步请求完成,因此能捕获到异常。
正确的异常捕获方式
方式1:用StepVerifier验证反应式流(测试场景推荐)
StepVerifier是Reactor提供的测试工具,可帮你等待流完成并验证结果,包括异常:
WebClient webClient = WebClient.builder().build(); Mono<String> resultMono = webClient.get() .uri("https://httpbin.org/status/404") .retrieve() .bodyToMono(String.class); StepVerifier.create(resultMono) .expectError(WebClientResponseException.NotFound.class) .verify();
方式2:手动阻塞等待(简单直接)
如果不想用StepVerifier,可在subscribe后让测试线程手动等待,比如用CountDownLatch:
CountDownLatch latch = new CountDownLatch(1); WebClient.builder().build() .get() .uri("https://httpbin.org/status/404") .retrieve() .bodyToMono(String.class) .subscribe( s -> { System.out.println("Success: " + s); latch.countDown(); }, t -> { System.out.println("Failure: " + t.getMessage()); latch.countDown(); }); // 等待异步操作完成,超时时间设为5秒 latch.await(5, TimeUnit.SECONDS);
方式3:非测试环境的正确姿势
在Spring WebFlux等业务环境中,框架会自动管理异步流的生命周期,此时你写的三个错误处理逻辑都能正常生效。比如在Controller中返回Mono<String>:
@GetMapping("/test") public Mono<String> test() { return WebClient.builder().build() .get() .uri("https://httpbin.org/status/404") .retrieve() .bodyToMono(String.class) .onErrorResume(t -> { log.warn("请求失败: {}", t.getMessage()); return Mono.just("Fallback Content"); }); }
补充:你的三个尝试本身没问题
你写的三种错误处理逻辑(传入错误Consumer、onErrorReturn、onErrorResume)本身是正确的,只是在JUnit测试中因为未等待异步操作完成,导致代码没机会执行而已。
内容的提问来源于stack exchange,提问作者Sergey Zolotarev
相关产品推荐
相关产品推荐

