Spring Cloud Gateway MVC网关过滤器异常处理方案咨询
Spring Cloud Gateway MVC 异常处理指南
一、ControllerAdvice 无法处理 GatewayFilter 内的异常
ControllerAdvice 仅负责拦截 Spring MVC 控制器(@Controller/@RestController)及其方法抛出的异常,而 GatewayFilter 属于网关请求转发链路的一部分,执行流程独立于 MVC 控制器的生命周期,所以ControllerAdvice 不能处理 GatewayFilter 内的异常。
二、Gateway MVC 过滤器异常的处理方案
针对你用 RouterFunctions 定义路由、自定义 CircuitBreaker 过滤器的场景,以下是几种可靠的异常处理方式:
1. 在自定义过滤器内直接捕获异常并返回 JSON
在你的 CircuitBreaker 过滤器逻辑中,捕获超时/熔断异常,直接构造 JSON 响应返回:
public class CustomCircuitBreakerFilter implements GatewayFilter { private final ObjectMapper objectMapper; public CustomCircuitBreakerFilter(ObjectMapper objectMapper) { this.objectMapper = objectMapper; } @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { return chain.filter(exchange) .onErrorResume(TimeoutException.class, ex -> { // 构造自定义错误响应体 Map<String, Object> errorResp = new HashMap<>(); errorResp.put("code", HttpStatus.GATEWAY_TIMEOUT.value()); errorResp.put("message", "请求超时,触发服务熔断"); // 设置响应状态和类型 exchange.getResponse().setStatusCode(HttpStatus.GATEWAY_TIMEOUT); exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON); // 写入响应 try { byte[] bytes = objectMapper.writeValueAsBytes(errorResp); DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes); return exchange.getResponse().writeWith(Mono.just(buffer)); } catch (JsonProcessingException e) { return exchange.getResponse().setComplete(); } }); } }
2. 实现全局异常处理器 ErrorWebExceptionHandler
Spring Cloud Gateway MVC 提供了 ErrorWebExceptionHandler 接口,专门用于处理网关链路中的所有异常(包括过滤器内的异常)。实现该接口做全局统一处理:
@Component @Order(Ordered.HIGHEST_PRECEDENCE) // 确保优先级高于默认处理器 public class GatewayGlobalErrorHandler implements ErrorWebExceptionHandler { private final ObjectMapper objectMapper; public GatewayGlobalErrorHandler(ObjectMapper objectMapper) { this.objectMapper = objectMapper; } @Override public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) { HttpStatus status = HttpStatus.INTERNAL_SERVER_ERROR; String msg = "服务处理异常"; // 根据异常类型定制响应 if (ex instanceof TimeoutException) { status = HttpStatus.GATEWAY_TIMEOUT; msg = "请求超时,触发熔断"; } else if (ex instanceof CircuitBreakerOpenException) { status = HttpStatus.SERVICE_UNAVAILABLE; msg = "服务熔断,暂时无法访问"; } // 构造响应 Map<String, Object> errorBody = new HashMap<>(); errorBody.put("code", status.value()); errorBody.put("message", msg); exchange.getResponse().setStatusCode(status); exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON); try { DataBuffer buffer = exchange.getResponse().bufferFactory() .wrap(objectMapper.writeValueAsBytes(errorBody)); return exchange.getResponse().writeWith(Mono.just(buffer)); } catch (JsonProcessingException e) { return exchange.getResponse().setComplete(); } } }
3. 结合熔断组件的 Fallback 机制
如果使用 Resilience4j 等熔断组件,可以直接配置 Fallback 端点,在熔断触发时转发到该端点返回 JSON:
// 配置 CircuitBreaker 过滤器工厂 @Bean public CircuitBreakerGatewayFilterFactory circuitBreakerFilterFactory() { CircuitBreakerGatewayFilterFactory factory = new CircuitBreakerGatewayFilterFactory(); factory.setCircuitBreakerConfig(CircuitBreakerConfig.custom() .failureRateThreshold(50) .waitDurationInOpenState(Duration.ofSeconds(10)) .build()); return factory; } // 定义路由时指定 Fallback @Bean public RouterFunction<ServerResponse> gatewayRoutes(CircuitBreakerGatewayFilterFactory cbFactory) { return RouterFunctions.route() .path("/api/**", () -> RouterFunctions.route() .GET("/**", req -> ServerResponse.ok().build()) .filter(cbFactory.apply(config -> config.setName("apiCircuitBreaker") .setFallbackUri("forward:/fallback/api-timeout"))) .build()) .build(); } // 定义 Fallback 处理路由 @Bean public RouterFunction<ServerResponse> fallbackRoutes() { return RouterFunctions.route() .GET("/fallback/api-timeout", req -> ServerResponse.status(HttpStatus.GATEWAY_TIMEOUT) .contentType(MediaType.APPLICATION_JSON) .bodyValue(Map.of("code", 504, "message", "请求超时,服务已熔断"))) .build(); }
关键注意事项
- 自定义
ErrorWebExceptionHandler时,需添加@Order(Ordered.HIGHEST_PRECEDENCE)确保其优先于默认异常处理器执行。 - 熔断组件配置时,要明确指定需要捕获的异常类型,避免遗漏超时、熔断等异常。
内容的提问来源于stack exchange,提问作者user3197674
相关产品推荐
相关产品推荐

