WebClient错误时返回ResponseEntity而非抛异常的Java17实现方案
WebClient处理错误状态码返回ResponseEntity的解决方案
问题背景
我此前从未使用过WebClient,现需通过它向外部URL发送POST请求,需求如下:
- 收到204状态码时正常继续流程
- 收到错误状态码时返回包含错误信息的ResponseEntity
但当前WebClient遇到错误状态码时会直接抛出异常,无法返回预期的ResponseEntity。尝试过onStatus的多种写法,要么无效,要么只能获取状态码但无法携带错误信息;不想通过try-catch捕获WebClientResponseException(担心代码评审不通过),也不想使用已废弃的exchange()方法,寻求Java 17环境下的可行方案。
初始代码:
public ResponseEntity<Void> post(String uri, User value) { return webClient.post() .uri(uri) .contentType(MediaType.APPLICATION_JSON) .bodyValue(value) .retrieve() // 原代码拼写错误为retreive .toEntity(Void.class) .timeout(properties.getTimeout()) .retryWhen(retry .filter(this::filterError) .doBefore(log.error("error message..."))) // 原代码doBefore用法有误 .block(); }
可行解决方案
核心思路是在onStatus回调中,将错误响应转换为包含错误状态码和信息的ResponseEntity,而非抛出异常或返回空值。以下提供两种适配不同需求的实现:
方案1:保持ResponseEntity,用响应头携带错误信息
如果必须维持返回类型为ResponseEntity<Void>,可以将错误信息存入自定义响应头:
public ResponseEntity<Void> post(String uri, User value) { return webClient.post() .uri(uri) .contentType(MediaType.APPLICATION_JSON) .bodyValue(value) .retrieve() .onStatus(HttpStatus::isError, clientResponse -> { // 读取错误响应体内容 return clientResponse.bodyToMono(String.class) .map(errorMsg -> { // 构造包含错误状态码和信息的ResponseEntity HttpHeaders headers = new HttpHeaders(); headers.add("X-Error-Detail", errorMsg); return ResponseEntity.status(clientResponse.statusCode()) .headers(headers) .build(); }); }) .toEntity(Void.class) .timeout(properties.getTimeout()) .retryWhen(retry .filter(this::filterError) .doBeforeRetry(signal -> log.error("准备重试,错误原因:{}", signal.failure().getMessage()))) .block(); }
方案2:调整返回类型为ResponseEntity,用响应体携带错误信息
如果允许调整返回类型,直接将错误信息放入响应体更直观:
public ResponseEntity<String> post(String uri, User value) { return webClient.post() .uri(uri) .contentType(MediaType.APPLICATION_JSON) .bodyValue(value) .retrieve() .onStatus(HttpStatus::isError, clientResponse -> { // 读取错误响应体并直接作为ResponseEntity的body返回 return clientResponse.bodyToMono(String.class) .map(errorMsg -> ResponseEntity.status(clientResponse.statusCode()).body(errorMsg)); }) .toEntity(String.class) .timeout(properties.getTimeout()) .retryWhen(retry .filter(this::filterError) .doBeforeRetry(signal -> log.error("准备重试,错误原因:{}", signal.failure().getMessage()))) .block(); }
关键说明
onStatus的正确用法:通过clientResponse.bodyToMono(String.class)读取错误响应体,再映射为目标ResponseEntity,避免抛出异常。- 修正原代码问题:原代码中
retreive拼写错误(应为retrieve),doBefore需改为doBeforeRetry才能正确在重试前打印日志。 - 重试逻辑保留:原有重试逻辑不受影响,错误状态下的
ResponseEntity会正常返回,不会触发重试(除非你的filterError方法包含错误状态码的重试逻辑)。
内容的提问来源于stack exchange,提问作者Zoltan514
相关产品推荐
相关产品推荐

