前言

在微服务架构中,API网关作为系统的唯一入口,承担着路由转发、负载均衡、安全认证、限流熔断等核心职责。Spring Cloud Gateway 作为 Spring 生态中的第二代网关,基于 Spring 5、Spring Boot 2 和 Project Reactor 构建,具备非阻塞、高性能的特性。

随着 Spring Cloud 2026.x 版本的发布,Gateway 模块迎来了多项重要更新:

  • 支持基于 Virtual Threads 的请求处理优化
  • 全新的限流熔断集成方案
  • 增强的过滤器链管理机制

本文将结合实战代码,深入探讨 Spring Cloud Gateway 2026.x 中自定义过滤器链的设计与限流熔断策略的实现。

一、环境准备与基础配置

1.1 依赖配置

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
    <version>4.5.2</version>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
    <version>3.2.0</version>
</dependency>
<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-ratelimiter</artifactId>
    <version>2.3.0</version>
</dependency>

1.2 基础路由配置

spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: lb://user-service
          predicates:
            - Path=/api/user/**
          filters:
            - StripPrefix=2
            
        - id: order-service
          uri: lb://order-service
          predicates:
            - Path=/api/order/**
          filters:
            - StripPrefix=2
            
      globalcors:
        cors-configurations:
          '[/**]':
            allowedOrigins: "*"
            allowedMethods:
              - GET
              - POST
              - PUT
              - DELETE
            allowedHeaders: "*"
            maxAge: 3600

二、自定义过滤器链设计

Spring Cloud Gateway 的过滤器分为 GatewayFilter(针对特定路由)和 GlobalFilter(全局生效)。2026.x 版本增强了过滤器的排序和链式管理能力。

2.1 自定义认证过滤器

@Component
@Order(-100) // 优先级最高,最先执行
public class AuthGlobalFilter implements GlobalFilter {

    private static final Logger log = LoggerFactory.getLogger(AuthGlobalFilter.class);

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String token = request.getHeaders().getFirst("Authorization");

        // 白名单路径跳过认证
        String path = request.getURI().getPath();
        if (isWhitelist(path)) {
            return chain.filter(exchange);
        }

        // Token 验证逻辑
        if (StringUtils.isEmpty(token) || !token.startsWith("Bearer ")) {
            log.warn("未授权访问: {}", path);
            return buildUnauthorizedResponse(exchange);
        }

        try {
            // 解析 Token 并验证
            Claims claims = JwtUtil.parseToken(token.substring(7));
            // 将用户信息放入请求头传递给下游
            ServerHttpRequest modifiedRequest = request.mutate()
                    .header("X-User-Id", claims.getUserId())
                    .header("X-User-Role", claims.getRole())
                    .build();

            return chain.filter(exchange.mutate()
                    .request(modifiedRequest)
                    .build());
        } catch (Exception e) {
            log.error("Token 验证失败", e);
            return buildUnauthorizedResponse(exchange);
        }
    }

    private boolean isWhitelist(String path) {
        List<String> whitelist = Arrays.asList(
                "/api/auth/login",
                "/api/auth/register",
                "/api/public/**"
        );
        return whitelist.stream()
                .anyMatch(pattern -> PathMatchUtil.match(pattern, path));
    }

    private Mono<Void> buildUnauthorizedResponse(ServerWebExchange exchange) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        
        String body = """
            {
                "code": 401,
                "message": "未授权访问,请先登录",
                "data": null
            }
            """;
        
        DataBuffer buffer = response.bufferFactory().wrap(body.getBytes());
        return response.writeWith(Mono.just(buffer));
    }
}

2.2 请求日志过滤器

@Component
@Order(-50)
public class RequestLogFilter implements GlobalFilter {

    private static final Logger log = LoggerFactory.getLogger(RequestLogFilter.class);

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String requestId = UUID.randomUUID().toString();
        
        // 记录请求开始时间
        exchange.getAttributes().put("startTime", System.currentTimeMillis());
        exchange.getAttributes().put("requestId", requestId);

        // 记录请求信息
        log.info("[{}] 请求开始: {} {} IP: {}", 
                requestId, 
                request.getMethod(), 
                request.getURI().getPath(),
                request.getRemoteAddress());

        return chain.filter(exchange)
                .doFinally(signalType -> {
                    long startTime = (long) exchange.getAttributes().get("startTime");
                    long duration = System.currentTimeMillis() - startTime;
                    
                    ServerHttpResponse response = exchange.getResponse();
                    log.info("[{}] 请求结束: 状态={} 耗时={}ms",
                            requestId,
                            response.getStatusCode(),
                            duration);
                });
    }
}

2.3 灰度发布过滤器

@Component
public class GrayReleaseGatewayFilterFactory extends 
        AbstractGatewayFilterFactory<GrayReleaseGatewayFilterFactory.Config> {

    public GrayReleaseGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();
            String userId = request.getHeaders().getFirst("X-User-Id");
            
            // 根据用户ID哈希判断是否走灰度版本
            if (StringUtils.isNotEmpty(userId) && isGrayUser(userId, config.getGrayRatio())) {
                URI grayUri = UriComponentsBuilder.fromUri(exchange.getAttribute(
                        ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR))
                        .host(config.getGrayServiceHost())
                        .build()
                        .toUri();
                
                exchange.getAttributes().put(
                        ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR, 
                        grayUri);
                
                log.info("灰度路由: 用户{} 路由到灰度版本 {}", userId, grayUri);
            }
            
            return chain.filter(exchange);
        };
    }

    private boolean isGrayUser(String userId, int grayRatio) {
        // 使用一致性哈希确保同一用户始终走同一版本
        int hash = Math.abs(userId.hashCode()) % 100;
        return hash < grayRatio;
    }

    public static class Config {
        private String grayServiceHost;
        private int grayRatio = 10; // 默认10%流量

        // getters and setters
        public String getGrayServiceHost() { return grayServiceHost; }
        public void setGrayServiceHost(String grayServiceHost) { 
            this.grayServiceHost = grayServiceHost; 
        }
        public int getGrayRatio() { return grayRatio; }
        public void setGrayRatio(int grayRatio) { this.grayRatio = grayRatio; }
    }
}

三、Resilience4j 限流熔断实战

Spring Cloud 2026.x 推荐使用 Resilience4j 作为熔断限流组件,替代已进入维护模式的 Hystrix。

3.1 限流器配置

@Configuration
public class RateLimiterConfig {

    @Bean
    public Customizer<Resilience4JCircuitBreakerFactory> defaultCustomizer() {
        return factory -> factory.configureDefault(id -> {
            // 熔断器配置
            CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom()
                    .failureRateThreshold(50) // 失败率阈值50%
                    .slowCallRateThreshold(50) // 慢调用率阈值50%
                    .slowCallDurationThreshold(Duration.ofSeconds(3)) // 慢调用定义:3s以上
                    .permittedNumberOfCallsInHalfOpenState(10) // 半开状态允许10次调用
                    .maxWaitDurationInHalfOpenState(Duration.ofSeconds(10))
                    .slidingWindowType(CircuitBreakerConfig.SlidingWindowType.COUNT_BASED)
                    .slidingWindowSize(100) // 滑动窗口大小
                    .minimumNumberOfCalls(20) // 最小调用次数
                    .waitDurationInOpenState(Duration.ofSeconds(30)) // 熔断后等待时间
                    .build();

            // 限流器配置
            io.github.resilience4j.ratelimiter.RateLimiterConfig rateLimiterConfig = 
                    io.github.resilience4j.ratelimiter.RateLimiterConfig.custom()
                    .limitRefreshPeriod(Duration.ofSeconds(1)) // 刷新周期
                    .limitForPeriod(100) // 每个周期允许请求数
                    .timeoutDuration(Duration.ofMillis(500)) // 超时时间
                    .build();

            TimeLimiterConfig timeLimiterConfig = TimeLimiterConfig.custom()
                    .timeoutDuration(Duration.ofSeconds(5)) // 全局超时5s
                    .build();

            return new Resilience4JConfigBuilder(id)
                    .circuitBreakerConfig(circuitBreakerConfig)
                    .rateLimiterConfig(rateLimiterConfig)
                    .timeLimiterConfig(timeLimiterConfig)
                    .build();
        });
    }
}

3.2 自定义限流过滤器

@Component
public class RateLimitFilter implements GlobalFilter, Ordered {

    private final RateLimiterRegistry rateLimiterRegistry;
    private static final Logger log = LoggerFactory.getLogger(RateLimitFilter.class);

    public RateLimitFilter(RateLimiterRegistry rateLimiterRegistry) {
        this.rateLimiterRegistry = rateLimiterRegistry;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String userId = exchange.getRequest().getHeaders().getFirst("X-User-Id");
        String limitKey = StringUtils.isNotEmpty(userId) ? userId : "anonymous";
        
        // 为每个用户创建独立的限流器
        RateLimiter rateLimiter = rateLimiterRegistry.rateLimiter("user-" + limitKey, 
                io.github.resilience4j.ratelimiter.RateLimiterConfig.custom()
                        .limitForPeriod(50) // 每秒50次请求
                        .limitRefreshPeriod(Duration.ofSeconds(1))
                        .build());

        if (rateLimiter.acquirePermission()) {
            return chain.filter(exchange);
        } else {
            log.warn("用户{} 请求被限流", limitKey);
            return buildRateLimitResponse(exchange);
        }
    }

    private Mono<Void> buildRateLimitResponse(ServerWebExchange exchange) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        response.getHeaders().set("Retry-After", "1");

        String body = """
            {
                "code": 429,
                "message": "请求过于频繁,请稍后再试",
                "data": null
            }
            """;

        DataBuffer buffer = response.bufferFactory().wrap(body.getBytes());
        return response.writeWith(Mono.just(buffer));
    }

    @Override
    public int getOrder() {
        return -80; // 在认证之后执行
    }
}

3.3 熔断降级处理

@Component
public class CircuitBreakerFilter implements GatewayFilter, Ordered {

    private final ReactiveCircuitBreakerFactory circuitBreakerFactory;
    private static final Logger log = LoggerFactory.getLogger(CircuitBreakerFilter.class);

    public CircuitBreakerFilter(ReactiveCircuitBreakerFactory circuitBreakerFactory) {
        this.circuitBreakerFactory = circuitBreakerFactory;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String routeId = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_PREDICATE_MATCHED_PATH_ATTR);
        
        ReactiveCircuitBreaker circuitBreaker = circuitBreakerFactory.create(
                "circuit-breaker-" + routeId);

        return circuitBreaker.run(
                chain.filter(exchange),
                throwable -> {
                    log.error("服务熔断触发: {}", throwable.getMessage());
                    return buildFallbackResponse(exchange, throwable);
                }
        );
    }

    private Mono<Void> buildFallbackResponse(ServerWebExchange exchange, Throwable throwable) {
        ServerHttpResponse response = exchange.getResponse();
        
        HttpStatus status;
        String message;
        
        if (throwable instanceof TimeoutException) {
            status = HttpStatus.GATEWAY_TIMEOUT;
            message = "服务请求超时,请稍后重试";
        } else if (throwable instanceof CallNotPermittedException) {
            status = HttpStatus.SERVICE_UNAVAILABLE;
            message = "服务暂时不可用,已触发熔断保护";
        } else {
            status = HttpStatus.INTERNAL_SERVER_ERROR;
            message = "服务异常,请稍后重试";
        }

        response.setStatusCode(status);
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);

        String body = String.format("""
            {
                "code": %d,
                "message": "%s",
                "data": null
            }
            """, status.value(), message);

        DataBuffer buffer = response.bufferFactory().wrap(body.getBytes());
        return response.writeWith(Mono.just(buffer));
    }

    @Override
    public int getOrder() {
        return -20;
    }
}

四、过滤器链整合与最佳实践

4.1 过滤器执行顺序配置

过滤器 Order 说明
RequestLogFilter -100 请求日志记录(最先)
AuthGlobalFilter -80 认证授权
RateLimitFilter -50 限流控制
GrayReleaseFilter -30 灰度发布路由
CircuitBreakerFilter -20 熔断保护
默认过滤器 0 Spring Gateway 内置过滤器
后置过滤器 100+ 响应处理

4.2 完整的路由配置示例

spring:
  cloud:
    gateway:
      routes:
        - id: order-service
          uri: lb://order-service
          predicates:
            - Path=/api/order/**
          filters:
            - StripPrefix=2
            - name: GrayRelease
              args:
                grayServiceHost: order-service-gray
                grayRatio: 20
            - name: CircuitBreaker
              args:
                name: order-service-circuitbreaker
                fallbackUri: forward:/fallback/order
      default-filters:
        - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin

五、性能优化建议

5.1 启用 Virtual Threads 支持

spring:
  threads:
    virtual:
      enabled: true  # Spring Boot 3.3+ 原生支持虚拟线程
      
  reactor:
    scheduler:
      virtual-threads: true

5.2 Netty 服务端优化

@Configuration
public class NettyConfig {

    @Bean
    public NettyServerCustomizer nettyServerCustomizer() {
        return httpServer -> httpServer
                .tcpConfiguration(tcpServer -> tcpServer
                        .option(ChannelOption.SO_BACKLOG, 1024)
                        .option(ChannelOption.SO_REUSEADDR, true)
                        .option(ChannelOption.TCP_NODELAY, true)
                )
                .httpRequestDecoder(spec -> spec
                        .maxInitialLineLength(4096)
                        .maxHeaderSize(8192)
                        .maxChunkSize(8192)
                );
    }
}

总结

本文深入探讨了 Spring Cloud Gateway 2026.x 的核心特性,包括:

  1. 自定义过滤器链:实现了认证、日志、灰度发布等典型场景的过滤器
  2. Resilience4j 限流熔断:基于最新版本的 Resilience4j 实现了精细化的限流熔断策略
  3. 最佳实践:过滤器执行顺序、性能优化配置

Spring Cloud Gateway 2026.x 结合虚拟线程和响应式编程模型,能够更好地支撑高并发场景下的 API 网关需求。在实际生产环境中,建议结合监控系统(如 Prometheus + Grafana)实时观测网关的 QPS、延迟、熔断触发等指标,持续优化配置参数。


参考资料:

  • Spring Cloud Gateway 官方文档: https://docs.spring.io/spring-cloud-gateway/reference/
  • Resilience4j 官方文档: https://resilience4j.readme.io/
  • Spring Cloud 2026.x Release Notes
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐