升级Spring Boot 3.0.x后,HttpMediaTypeNotSupportedException返回403而非415问题
问题排查:Spring Boot 3.0.0中HttpMediaTypeNotSupportedException返回403而非415
现象说明
- 在Spring Boot 2.7.18版本中,执行以下测试用例可正常通过,接口返回415 UNSUPPORTED_MEDIA_TYPE状态码:
@Test public void testInvalidMessage() { final ResponseEntity<String> responseEntity = testRestTemplate.withBasicAuth("user", "password") .postForEntity("/v1", "NOT_VALID_JSON", String.class); assertThat(responseEntity).isNotNull(); assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.UNSUPPORTED_MEDIA_TYPE); }
- 升级至Spring Boot 3.0.0后,相同测试用例执行时,接口返回403 FORBIDDEN状态码,不符合
HttpMediaTypeNotSupportedException应返回415的规范。
关联Controller代码
@RestController("MyController") @RequestMapping(MyController.ENDPOINT) public class MyController { private final static Logger logger = LoggerFactory.getLogger(MyController.class); public static final String ENDPOINT = "/v1"; @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) @Operation(summary = "Requests for a particular operation.") public ResponseEntity<XYZ> requestGrant(@RequestBody XYZRequest xyzRequest, @RequestHeader HttpHeaders headers) throws Exception { logger.info("Received request: {}", xyzRequest); // other logic here } }
排查与解决方向
1. 修正测试请求的Content-Type头设置
Spring Boot 3.0基于Spring Framework 6.0,Spring Security的拦截逻辑有调整:未显式指定Content-Type的POST请求,可能被Security拦截返回403,而非到达Controller触发415异常。
修改测试用例,添加Content-Type: application/json头(即使请求体是无效JSON):
@Test public void testInvalidMessage() { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); HttpEntity<String> requestEntity = new HttpEntity<>("NOT_VALID_JSON", headers); final ResponseEntity<String> responseEntity = testRestTemplate.withBasicAuth("user", "password") .postForEntity("/v1", requestEntity, String.class); assertThat(responseEntity).isNotNull(); assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.UNSUPPORTED_MEDIA_TYPE); }
2. 检查Spring Security的CSRF配置
Spring Security 6.0默认开启CSRF保护,未携带CSRF令牌的POST请求会被拦截返回403。若你的业务场景不需要CSRF保护,可在配置中关闭:
@Configuration public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.csrf(csrf -> csrf.disable()); // 其他安全配置 return http.build(); } }
3. 校验全局异常处理器逻辑
检查项目中是否存在自定义的@RestControllerAdvice全局异常处理器,确认是否错误地将HttpMediaTypeNotSupportedException映射为403状态码。若存在,修正为返回415:
@RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(HttpMediaTypeNotSupportedException.class) public ResponseEntity<String> handleMediaTypeNotSupported(HttpMediaTypeNotSupportedException ex) { return ResponseEntity.status(HttpStatus.UNSUPPORTED_MEDIA_TYPE) .body("不支持的媒体类型:" + ex.getMessage()); } }
内容的提问来源于stack exchange,提问作者Akanksha
相关产品推荐
相关产品推荐

