Spring Boot请求执行成功但客户端收到403错误的问题排查
问题根本原因与解决方案
根本原因
问题核心在于Spring Security与Spring MVC的@ResponseStatus注解(尤其是带reason属性或用于自定义异常时)的交互冲突:
- 当方法标注了带
reason的@ResponseStatus,或者自定义异常标注了@ResponseStatus时,Spring MVC会通过response.sendError()来设置响应状态,这会触发一次ERROR请求分发(即请求转发到/error端点,由BasicErrorController处理)。 - 这次ERROR分发会再次经过Spring Security的Filter Chain,此时CSRF Token的上下文已经发生变化:原请求的CSRF Token属性可能已被清理,或者新的请求无法正确获取到有效的CSRF Token,导致CSRF校验失败,抛出
AccessDeniedException,最终返回403状态码。 - DELETE请求独有该问题,是因为POST请求的成功响应流程中,CSRF Token的刷新逻辑可能刚好能覆盖ERROR分发时的校验,而DELETE请求的响应流程没有这个机制,导致校验失败概率100%。
验证依据
你提到移除安全配置后,请求仍触发ERROR dispatch但状态码正常——这说明ERROR分发本身是Spring MVC的行为,只是在有Security配置时,二次分发的请求过不了CSRF校验,才返回403。
解决方案
1. 移除@ResponseStatus的reason属性
将:
@ResponseStatus(code=HttpStatus.OK, reason="Succesfully deleted.")
改为:
@ResponseStatus(code=HttpStatus.OK)
这样Spring MVC会直接设置响应状态码,不会触发sendError()和后续的ERROR分发,自然不会经过二次CSRF校验。
2. 用全局异常处理器替代异常上的@ResponseStatus
删除EntityNotFoundException上的@ResponseStatus注解,创建全局异常处理器:
@RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(EntityNotFoundException.class) public ResponseEntity<String> handleEntityNotFound(EntityNotFoundException e) { return ResponseEntity.status(HttpStatus.NOT_FOUND).body(e.getMessage()); } }
这种方式直接返回响应,不会触发ERROR分发,避免二次Security校验。
3. (不推荐)忽略/error端点的CSRF校验
如果以上方案无法实施,可以在Security配置中添加对/error的CSRF忽略,但这会降低安全性:
http.csrf() .ignoringRequestMatchers("/api/login", "/error") // 新增/error // 其他配置...
内容的提问来源于stack exchange,提问作者DiTi
相关产品推荐
相关产品推荐

