Spring Webflux:Web与WebTestClient调用时抛出异常不一致问题咨询
原因分析
这不是Spring的Bug,而是运行环境与测试环境的Web框架上下文不一致导致的,常见触发场景有两种:
- 混合依赖导致环境差异
如果项目同时引入了spring-boot-starter-web(Spring MVC)和spring-boot-starter-webflux(Spring WebFlux)依赖,Spring Boot默认会优先启用MVC的DispatcherServlet作为请求处理核心。此时实际运行时控制器在MVC环境下执行,缺少参数/头会抛出MVC风格的MissingServletRequestParameterException/MissingRequestHeaderException;而@WebFluxTest是WebFlux专属切片测试,会强制启用响应式处理链,抛出WebFlux原生的MissingRequestValueException。 - 异常转换配置未加载
纯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
相关产品推荐
相关产品推荐

