一、核心概念

1. Spring Cloud Gateway 是什么?

Spring Cloud Gateway 是 Spring 官方基于 Project Reactor 构建的响应式 API 网关,用于微服务架构中的统一入口,具备高性能、异步非阻塞、支持 WebSocket 等特性。

✅ 替代 Zuul 1.x(同步阻塞),是当前 Spring Cloud 推荐的网关组件。


2. 过滤器(Filter)核心概念

Gateway 的过滤器分为两种类型:

类型 说明
GatewayFilter 局部过滤器:作用于特定路由,可修改请求/响应
GlobalFilter 全局过滤器:作用于所有路由,通常用于鉴权、日志、限流等

本文重点:使用 GatewayFilter 实现 添加请求头,使用 RequestRateLimiter 实现 限流


3. 常见过滤器功能

功能 示例
添加/修改请求头 AddRequestHeader, AddResponseHeader
路由重写 RewritePath
请求限流 RequestRateLimiter
身份认证 AuthenticationFilter(自定义)
跨域处理 CorsFilter

二、操作步骤(非常详细)

步骤 1:创建 Spring Boot 项目并添加依赖

<!-- pom.xml -->
<dependencies>
    <!-- Spring Cloud Gateway(已包含 WebFlux) -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>

    <!-- 限流依赖:Redis + Reactor Redis -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
    </dependency>

    <!-- Eureka Client(可选:服务发现) -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
</dependencies>

⚠️ 注意:

  • 不能引入 spring-boot-starter-web(会冲突,Gateway 基于 WebFlux)
  • 若使用限流,必须引入 spring-boot-starter-data-redis-reactive

步骤 2:配置 application.yml(基于配置方式)

server:
  port: 8080

spring:
  application:
    name: api-gateway

  cloud:
    gateway:
      discovery:
        locator:
          enabled: true  # 开启服务发现路由(自动映射服务名为路由)
          lower-case-service-id: true
      routes:
        - id: user-service-route
          uri: lb://user-service  # lb: 负载均衡,user-service: Eureka 注册名
          predicates:
            - Path=/api/users/**
          filters:
            # 1. 添加请求头
            - AddRequestHeader=X-Request-Source, gateway
            - AddRequestHeader=X-Trace-Id, ${random.uuid}
            # 2. 限流过滤器
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10   # 每秒补充10个令牌(令牌桶容量)
                redis-rate-limiter.burstCapacity: 20  # 桶最大容量20
                key-resolver: "#{@apiKeyResolver}"    # 限流键的解析器(SpEL引用Bean)

    # Redis 配置(限流用)
    redis:
      host: localhost
      port: 6379

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

步骤 3:实现限流键解析器(KeyResolver)

限流需要知道“按什么维度限流”,如:IP、用户ID、API Key 等。

场景:按客户端 IP 限流

@Configuration
public class GatewayConfig {

    /**
     * 按客户端 IP 限流
     */
    @Bean
    public KeyResolver apiKeyResolver() {
        return exchange -> {
            // 获取客户端 IP
            String ip = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
            return Mono.just(ip);
        };
    }

    /**
     * 按用户请求路径限流(例如:每个路径独立限流)
     */
    @Bean
    public KeyResolver pathKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getURI().getPath());
    }
}

KeyResolver 返回 Mono<String>,支持异步。


步骤 4:使用 Java 代码配置路由(替代 YAML,可选)

@Configuration
public class GatewayRouteConfig {

    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
            .route("user-service-route", r -> r.path("/api/users/**")
                .filters(f ->
                    f.addRequestHeader("X-Request-Source", "gateway-java")
                     .addRequestHeader("X-Trace-Id", UUID.randomUUID().toString())
                     .requestRateLimiter(
                         c -> c.setRateLimiter(redisRateLimiter())
                               .setKeyResolver(apiKeyResolver())
                     )
                )
                .uri("lb://user-service")
            )
            .build();
    }

    @Bean
    @Synchronized
    public KeyResolver apiKeyResolver() {
        return exchange -> {
            String ip = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
            return Mono.just(ip);
        };
    }

    @Bean
    public RedisRateLimiter redisRateLimiter() {
        return new RedisRateLimiter(10, 20); // replenishRate=10, burstCapacity=20
    }
}

⚠️ 若使用 Java 配置,需注释掉 spring.cloud.gateway.routes 配置。


步骤 5:启动 Redis 服务

限流依赖 Redis 存储令牌桶状态。

  • 启动本地 Redis:redis-server
  • 或使用 Docker:
docker run -d -p 6379:6379 --name redis redis:alpine

步骤 6:验证功能

1. 添加请求头验证

调用网关接口:

curl -v http://localhost:8080/api/users/1

user-service 中打印请求头,应看到:

X-Request-Source: gateway
X-Trace-Id: 550e8400-e29b-41d4-a716-446655440000

2. 限流验证

快速连续请求(如 30 次/秒):

for i in {1..30}; do curl -s http://localhost:8080/api/users/1 & done

预期结果:

  • 前 20 次成功(burstCapacity)
  • 超出后返回 429 Too Many Requests

三、常见错误与解决方案

错误现象 原因 解决方案
ClassCastException: ServletRequest 引入了 spring-boot-starter-web 移除该依赖
NoSuchBeanException: KeyResolver KeyResolver Bean 未注册 检查 @Bean 和配置类扫描
限流不生效 Redis 未启动或配置错误 检查 Redis 连接、SpEL 表达式 #{@beanName}
路由 404 uri 格式错误或服务未注册 检查服务名、Eureka 注册状态
RequestRateLimiter 报错 缺少 spring-boot-starter-data-redis-reactive 添加依赖

四、注意事项

  1. 线程模型:Gateway 基于 Netty,不能阻塞,避免在过滤器中使用 Thread.sleep() 或同步 IO。
  2. SpEL 表达式key-resolver: "#{@beanName}" 必须使用 @ 符号引用 Spring Bean。
  3. Redis 数据结构:限流使用 Redis 的 ListString 存储令牌状态。
  4. 默认限流策略RedisRateLimiter 使用 令牌桶算法
  5. 服务发现lb://service-name 依赖 Eureka/Nacos 等注册中心。

五、使用技巧

  1. 动态刷新路由:结合 Spring Cloud ConfigNacos 实现路由热更新。
  2. 自定义过滤器:实现 GatewayFilterGlobalFilter 做签名校验、日志记录等。
@Bean
public GlobalFilter loggingFilter() {
    return (exchange, chain) -> {
        System.out.println("请求进入: " + exchange.getRequest().getURI());
        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
            System.out.println("响应发出: " + exchange.getResponse().getStatusCode());
        }));
    };
}
  1. 跨域配置
spring:
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]':
            allowedOrigins: "*"
            allowedMethods: "*"
            allowedHeaders: "*"
  1. 健康检查端点:访问 /actuator/gateway/routes 查看当前路由。

六、最佳实践与性能优化

实践 说明
✅ 使用 YAML 配置路由 简洁、易维护
✅ 限流键选择合理维度 如 IP、用户ID,避免全局限流误伤
✅ Redis 高可用 生产环境使用 Redis Cluster 或 Sentinel
✅ 启用 Actuator 监控 查看网关状态、路由、过滤器
✅ 避免复杂逻辑在网关 网关应轻量,复杂业务下沉到微服务
✅ 使用 HTTPS 配置 SSL 保证安全
✅ 限流降级 结合 Resilience4j 实现限流后降级响应

七、总结

  • 添加请求头:使用 AddRequestHeader 过滤器,简单高效。
  • 限流:基于 RedisRateLimiter + KeyResolver + Redis,实现分布式限流。
  • 响应式架构:理解 WebFlux 和非阻塞编程模型是使用 Gateway 的基础。
  • 未来趋势:Spring Cloud Gateway 是微服务网关的主流选择,支持 Kubernetes、Service Mesh 集成。

📌 快速口诀:
一网关,两过滤,加头限流全靠它;YAML配置最方便,Redis支撑不超载。