You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 05:05:36