Java WebFilter响应式网关捕获全局Gateway路由异常
SpringCloudGateway基于WebFlux,无法使用@ControllerAdvice。全局异常捕获可通过ErrorWebExceptionHandler实现框架兜底,捕获所有未处理异常并返回JSON响应;也可通过GlobalFilter结合onErrorResume拦截异常并终止链路,但需处理限流等组件异常穿透问题,避免循环异常。
在 Spring Cloud Gateway 响应式架构中,全局异常捕获仅有两种有效途径:使用 ErrorWebExceptionHandler 实现框架级兜底,或通过 GlobalFilter 在链路层面拦截。传统 Servlet 的 @ControllerAdvice 在 WebFlux 环境下无法生效——这一点需提前明确,避免走弯路。

之所以如此限定,是因为 Gateway 基于 WebFlux,不经过 Servlet 容器的 Filter 链,自然也无法使用 javax.servlet.Filter 捕获路由异常。真正有效的只有这两类,但它们的定位和适用场景差异较大,使用前需明确区分。
用 ErrorWebExceptionHandler 替换默认错误处理器
这是最推荐的全局兜底方案,没有之一。它能捕获所有未被上游过滤器处理的异常——包括路由匹配失败、转发超时、下游服务不可达、限流触发等,且优先级高于 Spring Boot 自带的默认实现。
- 实现
ErrorWebExceptionHandler接口,重写handle()方法 - 添加
@Component和@Order(-1)注解,确保优先加载 - 先检查
response.isCommitted(),避免重复写入已提交的响应 - 统一构造 JSON 响应体(例如
{"code":500,"message":"服务暂时不可用"}),并设置Content-Type: application/json - 对常见异常分类处理:
ResponseStatusException取状态码,TimeoutException返回 504,ConnectException返回 503
用 GlobalFilter 拦截并提前终止异常链
该方案适合在请求进入路由前进行前置校验(如鉴权、参数校验),或在路由执行后捕获转发过程中抛出的异常。但需注意,它不能直接捕获网关内部组件(如断路器、限流器)抛出的原始异常——除非这些组件显式抛出并被链路传递下来。
- 实现
GlobalFilter,使用@Order(-2)确保早于路由过滤器执行 - 在
chain.filter(exchange).onErrorResume(...)中捕获异常 - 区分异常类型:
ResponseStatusException直接设置对应状态码,否则设 500 并记录日志 - 调用
exchange.getResponse().setComplete()终止后续过滤器执行 - 避免在
onErrorResume中抛出新异常——否则会再次触发ErrorWebExceptionHandler,形成循环
注意限流、断路器等组件的异常穿透问题
像 RequestRateLimiter 或 Spring Cloud CircuitBreaker 抛出的异常,默认不会进入 GlobalFilter 的 onErrorResume,因为这些异常在独立过滤器中完成。如需统一处理,需换一种思路:
- 在配置中显式指定回退逻辑,例如限流失败时返回自定义响应体(需配合
redis-rate-limiter的denyEmptyResponse和自定义RateLimiter实现) - 让这些组件抛出标准
ResponseStatusException(如new ResponseStatusException(HttpStatus.TOO_MANY_REQUESTS)),以便被ErrorWebExceptionHandler统一接管 - 不建议在
GlobalFilter中重写限流过滤器逻辑——容易破坏原有的执行顺序和状态一致性
不要用 @ControllerAdvice
这条必须单独强调。该注解依赖 Spring MVC 的同步请求上下文,在 WebFlux 响应式网关中完全无效。网关没有 Controller 层,也不经过 DispatcherHandler 的异常处理流程。即使添加 @RestControllerAdvice,也不会产生任何效果——它只是摆设。
