如何在WebClient中通过retrieve优雅处理500错误码?
看起来你踩了WebClient retrieve()方法的一个常见坑——它默认只接受2xx的响应状态,非2xx(比如500)会直接抛出WebClientResponseException,而你直接用block()的时候,这个异常会被包装成ReactiveException抛出来,导致代码崩溃。我来帮你重构代码,优雅处理所有错误场景:
重构后的完整代码
private String generateOrder(ImportedOrderDetails importedOrderDetails) { Order requestBody = generateRequestBody(importedOrderDetails); return orderWebClient() .post() .body(Mono.just(requestBody), Order.class) .retrieve() // 第一步:处理非2xx的HTTP状态码(比如500、400) .onStatus(HttpStatus::isError, clientResponse -> { // 可以根据具体状态码定制错误信息,这里先统一处理 return Mono.error(new RuntimeException("调用第一个接口出错")); }) .bodyToMono(OrderResponse.class) // 第二步:处理业务逻辑判断 .flatMap(orderResponse -> { if (orderResponse.getResponseStatus().equals(SUCCESS)) { // 调用第二个WebClient的逻辑,这里假设返回Mono<String> return secondWebClient() // 示例:根据你的业务配置第二个请求(比如POST、设置参数等) .post() .bodyValue(/* 第二个请求的参数 */) .retrieve() .bodyToMono(String.class); } else { // 业务状态失败,返回指定字符串 return Mono.just("创建订单失败"); } }) // 第三步:捕获所有异常(包括HTTP错误、网络异常等) .onErrorResume(throwable -> Mono.just("调用第一个接口出错")) // 最后阻塞获取结果,此时所有错误都已被处理 .block(); }
关键部分说明
onStatus处理HTTP错误状态:
这个操作符专门用来捕获非2xx的响应状态(比如500服务器错误、400参数错误),我们在这里抛出一个自定义异常,后续由onErrorResume统一处理。如果需要区分不同错误类型(比如5xx和4xx返回不同信息),可以细化判断:.onStatus(status -> status.is5xxServerError(), res -> Mono.error(new RuntimeException("服务器内部错误"))) .onStatus(status -> status.is4xxClientError(), res -> Mono.error(new RuntimeException("请求参数错误")))flatMap串联业务逻辑:
当HTTP响应是200时,我们通过flatMap处理业务状态判断:如果业务状态成功,就发起第二个WebClient请求;否则直接返回业务错误字符串。这样整个逻辑都在Reactor流中完成,避免了提前block()导致的异常暴露。onErrorResume兜底捕获异常:
不管是onStatus抛出的自定义异常,还是请求过程中出现的网络异常、序列化异常等,都会被这个操作符捕获,返回我们想要的错误提示字符串,确保block()不会抛出未处理的异常。
为什么之前的修改会报错?
你之前的问题应该是错误处理逻辑没有嵌入到Reactor流中,比如只是在retrieve()后加了错误处理,但还是直接调用block()获取OrderResponse,这时候异常依然会被block()抛出。现在的方式是把所有逻辑(包括错误处理)都放在Mono链中,最后才block(),此时流已经处理了所有异常,只会返回正常的字符串结果。
内容的提问来源于stack exchange,提问作者bootlover123

