Spring自定义异常处理器调用正常,但返回结果被覆盖问题排查
检查WebClient异步处理与超时配置
WebClient是异步调用,先确认异常转换的时机是否正确:如果用反应式编程返回Mono/Flux,必须用onErrorMap把WebClientRequestException转换成MyAppException,不能在回调里手动抛出(脱离Spring异常处理链);如果用block()同步调用,要确保异常能被Spring的拦截器捕获。另外对比容器(如Tomcat)的server.connection-timeout和WebClient的responseTimeout:如果容器超时更短,会先返回504,此时你的异常处理逻辑虽执行,但响应已被容器发送。验证异常处理器的优先级
检查是否有其他@ControllerAdvice处理器或ErrorController实现类,它们的优先级可能比你的自定义处理器高,覆盖了响应。给你的ControllerExceptionHandler加上@Order(Ordered.HIGHEST_PRECEDENCE),确保它最先执行。同时排查是否存在第三方框架的异常处理器(比如Spring Security的异常处理),是否会拦截并修改响应。排查网关/代理的超时拦截
如果服务前有网关(Spring Cloud Gateway、Nginx等),直接绕过网关访问服务实例:如果此时能返回自定义的500响应,说明网关的超时配置(如Nginx的proxy_read_timeout)过短,提前返回了504;如果还是返回504,再排查服务内部。检查Reactor流中的异常传播
在反应式场景下,异常必须在Reactor流中正确传播。比如确保你的WebClient调用链是:webClient.get() .uri("/external-api") .retrieve() .bodyToMono(YourDto.class) .onErrorMap(WebClientRequestException.class, e -> new MyAppException("服务下线", e));而不是用
try-catch包裹block(),后者可能导致异常被抛到非Spring管理的线程,无法被@ControllerAdvice正确处理(虽然你说处理器被调用了,但仍需确认流的完整性)。排查容器与Spring Boot的错误响应配置
检查Spring Boot的server.error.*配置,比如server.error.path、server.error.whitelabel.enabled,是否启用了默认错误页面覆盖自定义响应。可以临时设置server.error.whitelabel.enabled=false,或者添加server.error.include-exception=true,看是否能看到自定义响应的内容。另外检查Tomcat等容器是否配置了自定义错误页面,是否会拦截500响应并替换为504。抓包验证实际响应
用curl或Wireshark抓包,直接请求服务实例,看服务实际发送的响应状态码和内容:- 如果抓包显示服务返回500,但客户端收到504,问题出在中间代理/网关;
- 如果抓包显示服务返回504,说明你的异常处理器返回的ResponseEntity被内部逻辑覆盖,需要调试Spring的响应处理链(比如在
DispatcherServlet或ExceptionHandlerExceptionResolver加断点)。
内容的提问来源于stack exchange,提问作者wxkevin

