@RestControllerAdvice搭配@ResponseStatus时前端无异常响应问题
问题背景
- 项目中使用
@RestControllerAdvice实现全局异常处理,逻辑为根据抛出的运行时异常类型返回对应的自定义响应。 - 本地调试、Postman发起请求时功能运行完全正常,但部署到Quality环境后,异常触发时前端无法接收到任何响应,Postman发起完全相同的请求却可正常获取返回结果。
- 经过约5小时排查,移除异常处理方法上的
@ResponseStatus注解后,异常发生时前端即可正常接收响应。 - 存在问题的
@RestControllerAdvice实现代码如下:
@RestControllerAdvice public class SftpExceptionHandler { @ExceptionHandler(FileTypeNotFoundException.class) @ResponseStatus(HttpStatus.NOT_FOUND) public GeneralResponse handlerRequestException(FileTypeNotFoundException ex) { return new GeneralResponse(HttpStatus.NOT_FOUND, ex.getMessage()); } @ExceptionHandler(IncorrectConsecutiveException.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public GeneralResponse handlerRequestException(IncorrectConsecutiveException ex) { return new GeneralResponse(HttpStatus.INTERNAL_SERVER_ERROR, ex.getMessage()); } @ExceptionHandler(InvalidBinaryFileException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) public GeneralResponse handlerRequestException(InvalidBinaryFileException ex) { return new GeneralResponse(HttpStatus.BAD_REQUEST, ex.getMessage()); } }
- 自定义异常示例代码如下:
public class InvalidBinaryFileException extends RuntimeException { private static final long serialVersionUID = 1L; public InvalidBinaryFileException(String message) { super(message); } }
问题原因
该问题是环境链路差异+@ResponseStatus底层生效逻辑共同导致的:
@ResponseStatus的核心作用是标记方法对应的HTTP响应状态码,Spring处理完该方法返回值后,不仅会把对应状态码写入响应头,还会向Servlet容器发起标准错误请求派发(即走Servlet的error dispatch流程)。- 本地调试、Postman直连后端服务测试时,请求不经过中间代理层,即使触发了错误派发,容器最终还是会将
GeneralResponse响应体正常返回,因此表现完全正常。 - Quality环境的前端调用链路一般会额外部署Nginx/API网关这类反向代理层,这类代理默认配置了错误拦截规则:只要检测到后端返回的响应走了错误派发流程、状态码为4xx/5xx,就会直接丢弃后端原始返回的响应体,要么返回网关预置的空白错误页,要么直接中断连接,前端自然收不到任何响应内容。
- Postman可以正常获取结果,基本都是因为测试时Postman请求的是后端服务直连地址,没有走前端访问时经过的网关层,不会触发拦截规则。
修复方案
- 直接移除异常处理方法上的
@ResponseStatus注解即可。此时返回的GeneralResponse会作为正常响应体返回,不会触发Servlet容器的错误派发流程,网关不会执行拦截,前端即可正常拿到响应内容。如果项目规范是在响应体中封装业务状态码、HTTP层统一返回200,这种方式完全适配。 - 如果需要让HTTP响应状态码和业务错误码保持对齐,不要使用
@ResponseStatus注解,直接在方法内注入HttpServletResponse手动设置状态码即可,该方式不会触发错误派发流程:
@ExceptionHandler(InvalidBinaryFileException.class) public GeneralResponse handlerRequestException(InvalidBinaryFileException ex, HttpServletResponse response) { response.setStatus(HttpStatus.BAD_REQUEST.value()); return new GeneralResponse(HttpStatus.BAD_REQUEST, ex.getMessage()); }
内容的提问来源于stack exchange,提问作者BugsOverflow
相关产品推荐
相关产品推荐

