You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用@ControllerAdvice处理Spring WebFlux中WebClient请求错误

核心原理

Spring WebFlux 中 WebClient 返回的 Mono/Flux 是冷流:只有当流被订阅时,请求才会真正发送,异常才会在执行链中传播。当前代码存在两个核心问题导致异常无法被全局拦截:

  1. 对外提供的send接口方法中没有执行WebClient调用逻辑,直接返回200状态,WebClient的流从未被触发订阅,自然不会产生异常
  2. 即使调用了WebClient,如果手动调用subscribe()触发流而非将流返回给Spring WebFlux核心容器管理,异常会落到自定义订阅的错误钩子,不会进入全局异常处理链
适配步骤

1. 修正自定义异常定义

确保自定义异常继承RuntimeException,支持接收错误信息、原始状态码参数:

public class WrongCredentialsException extends RuntimeException {
    private final int rawStatusCode;

    public WrongCredentialsException(String message, int rawStatusCode) {
        super(message);
        this.rawStatusCode = rawStatusCode;
    }

    public int getRawStatusCode() {
        return rawStatusCode;
    }
}

2. 修正WebClient调用逻辑

onStatus判断逻辑中,拿到错误响应后把状态码和错误体一起传入自定义异常抛出,避免响应体重复消费:

public Mono<TResponse> callRemoteService(Dto dto) {
    return webClient
            .post()
            .uri("/your/remote/api") // 替换为实际远程接口地址
            .contentType(MediaType.APPLICATION_FORM_URLENCODED)
            .body(
                    BodyInserters
                            .fromFormData("param1", dto.getParam1()) // 替换为实际表单参数
                            .with("param2", dto.getParam2())
            )
            .retrieve()
            .onStatus(HttpStatus::isError, response ->
                    response.bodyToMono(String.class)
                            .flatMap(errorBody -> Mono.error(new WrongCredentialsException(errorBody, response.statusCode().value())))
            )
            .bodyToMono(TResponse.class);
}

3. 修正Controller接口逻辑

必须将WebClient返回的响应流直接返回给Spring管理,由框架负责订阅触发请求,异常会自动沿执行链抛到全局处理器:

@PostMapping("/send")
public Mono<ResponseEntity<String>> send(@RequestBody Dto dto) {
    log.debug("An notification has been send to user");
    return callRemoteService(dto)
            .map(response -> ResponseEntity.ok("success"));
}

注意:绝对不要在Controller方法内部手动调用.subscribe()触发WebClient请求,否则异常脱离WebFlux主执行链,全局处理器无法捕获。

4. 修正全局异常处理器

补全错误响应字段,适配响应式执行链:

@ControllerAdvice
@Slf4j
public class ApplicationErrorHandler {

    @ExceptionHandler(WrongCredentialsException.class)
    public ResponseEntity<ErrorResponse> handleResponseException(WrongCredentialsException ex) {
        log.error("Error from WebClient - Status {}, Body {}", ex.getRawStatusCode(), ex.getMessage(), ex);

        ErrorResponse error = new ErrorResponse(
                "REMOTE_CALL_ERROR",
                ex.getMessage()
        );
        // 远程返回400时不要统一返回500,可根据实际业务调整状态码
        return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                .body(error);
    }
}
验证方式

启动服务后调用对外的/send接口,当远程服务返回400/500等错误状态时,会自动触发WrongCredentialsException抛出,全局处理器会捕获异常并返回结构化的错误信息给客户端,不会出现异常丢失的问题。

内容的提问来源于stack exchange,提问作者skyho

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 00:01:05