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

Spring Webflux:Web与WebTestClient调用时抛出异常不一致问题咨询

原因分析

这不是Spring的Bug,而是运行环境与测试环境的Web框架上下文不一致导致的,常见触发场景有两种:

  1. 混合依赖导致环境差异
    如果项目同时引入了spring-boot-starter-web(Spring MVC)和spring-boot-starter-webflux(Spring WebFlux)依赖,Spring Boot默认会优先启用MVC的DispatcherServlet作为请求处理核心。此时实际运行时控制器在MVC环境下执行,缺少参数/头会抛出MVC风格的MissingServletRequestParameterException/MissingRequestHeaderException;而@WebFluxTest是WebFlux专属切片测试,会强制启用响应式处理链,抛出WebFlux原生的MissingRequestValueException。
  2. 异常转换配置未加载
    纯WebFlux环境下,底层参数解析逻辑会直接抛出MissingRequestValueException,但部分自定义配置或第三方组件可能在运行时将其转换为MVC兼容异常,而切片测试中未加载这些配置,导致异常类型不一致。

解决方案

方案1:统一Web框架依赖(推荐)

如果应用目标是纯响应式架构,移除spring-boot-starter-web依赖,确保运行时和测试时都使用WebFlux环境。此时两端都会抛出MissingRequestValueException,只需在ControllerAdvice中处理该异常即可:

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(MissingRequestValueException.class)
    public Mono<ResponseEntity<ErrorResponse>> handleMissingRequestValue(MissingRequestValueException ex) {
        String message;
        if (ex.getParameterName() != null) {
            message = String.format("必填请求参数「%s」缺失", ex.getParameterName());
        } else if (ex.getHeaderName() != null) {
            message = String.format("必填请求头「%s」缺失", ex.getHeaderName());
        } else {
            message = ex.getMessage();
        }
        return Mono.just(
            ResponseEntity.status(HttpStatus.BAD_REQUEST)
                .body(new ErrorResponse(message))
        );
    }
}

方案2:兼容两种异常类型

如果必须保留混合依赖(不推荐),或需要兼容两种环境,在ControllerAdvice中同时处理MVC和WebFlux的异常:

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler({
        MissingServletRequestParameterException.class,
        MissingRequestHeaderException.class,
        MissingRequestValueException.class
    })
    public Mono<ResponseEntity<ErrorResponse>> handleMissingValues(Exception ex) {
        String message;
        HttpStatus status = HttpStatus.BAD_REQUEST;

        if (ex instanceof MissingServletRequestParameterException) {
            MissingServletRequestParameterException paramEx = (MissingServletRequestParameterException) ex;
            message = String.format("必填请求参数「%s」缺失", paramEx.getParameterName());
        } else if (ex instanceof MissingRequestHeaderException) {
            MissingRequestHeaderException headerEx = (MissingRequestHeaderException) ex;
            message = String.format("必填请求头「%s」缺失", headerEx.getHeaderName());
        } else if (ex instanceof MissingRequestValueException) {
            MissingRequestValueException valueEx = (MissingRequestValueException) ex;
            message = valueEx.getMessage();
            if (valueEx.getParameterName() != null) {
                message = String.format("必填请求参数「%s」缺失", valueEx.getParameterName());
            } else if (valueEx.getHeaderName() != null) {
                message = String.format("必填请求头「%s」缺失", valueEx.getHeaderName());
            }
        } else {
            message = "缺少必填的请求参数或头信息";
        }

        return Mono.just(ResponseEntity.status(status).body(new ErrorResponse(message)));
    }
}

方案3:对齐测试环境配置

如果坚持使用混合依赖且希望测试环境抛出MVC异常,可将测试类改为使用@WebMvcTest而非@WebFluxTest,确保测试时的请求处理链与运行时一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 02:52:17