Spring Cloud Gateway 网关与限流实战

在微服务架构里,API 网关是所有外部请求的统一入口。Spring Cloud Gateway 基于 Spring Boot 3 和 WebFlux 构建,提供路由转发、过滤器链、限流熔断等核心能力。本文从路由规则配置讲起,深入全局过滤器与自定义过滤器,最后覆盖 Redis 限流与生产部署的完整方案。

Spring Cloud Gateway 配图:蓝色渐变背景上中心漏斗网关连接多条管线,两侧阀门调节流量,扁平科技插画
网关:所有外部请求的统一入口,路由、过滤、限流都在这里完成

一、网关在微服务中的位置

没有网关的时候,前端需要直接调用每个微服务的地址,还要自己处理认证、跨域、限流。有了网关之后,所有请求先到网关,由网关决定路由到哪个服务,并统一处理横切逻辑。

网关的核心职责包括:路由转发(把 /api/user/** 转发给用户服务)、认证鉴权(校验 Token)、限流熔断(保护后端服务不被打垮)、日志监控(记录所有请求)。

职责说明
路由转发根据 URL 路径把请求分发到对应微服务
认证鉴权校验 JWT Token,把用户信息传递给下游服务
限流按用户或 IP 限制请求频率,防止过载
熔断降级下游服务异常时快速失败,返回降级响应
日志监控统一记录请求路径、耗时、状态码

二、路由配置实战

Spring Cloud Gateway 的路由配置非常直观。下面是一个完整的 application.yml 示例:

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
        - id: payment-service
          uri: lb://payment-service
          predicates:
            - Path=/api/pay/**
          filters:
            - StripPrefix=2

三个关键字段:id 是路由的唯一标识;uri 指定目标地址,lb:// 表示从注册中心(Nacos)负载均衡;predicates 是匹配条件,这里用 Path 做路径匹配;filters 是过滤器,StripPrefix=2 表示去掉路径前两级(/api/user → 转发给用户服务时变成 /)。

调试技巧:启动网关后访问 http://localhost:8080/actuator/gateway/routes 可以看到所有已加载的路由规则,方便排查路由不生效的问题。

三、全局过滤器:统一鉴权

全局过滤器(GlobalFilter)会作用于所有路由。最典型的用法是统一校验 Token:

@Component
public class AuthFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String path = exchange.getRequest().getURI().getPath();
        // 放行登录和注册接口
        if (path.contains("/api/user/login") || path.contains("/api/user/register")) {
            return chain.filter(exchange);
        }
        // 校验 Token
        String token = exchange.getRequest().getHeaders().getFirst("Authorization");
        if (token == null || !token.startsWith("Bearer ")) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        // 解析 Token,把用户 ID 传给下游
        String userId = parseToken(token.substring(7));
        ServerHttpRequest mutatedRequest = exchange.getRequest().mutate()
                .header("X-User-Id", userId)
                .build();
        return chain.filter(exchange.mutate().request(mutatedRequest).build());
    }

    private String parseToken(String token) {
        // 实际项目里用 JWT 库解析
        return "user_12345";
    }

    @Override
    public int getOrder() {
        return -100; // 优先级高,最先执行
    }
}

四、Redis 限流实战

网关最核心的保护能力是限流。Spring Cloud Gateway 内置了基于 Redis 的限流器,用令牌桶算法实现:

spring:
  cloud:
    gateway:
      routes:
        - id: order-service
          uri: lb://order-service
          predicates:
            - Path=/api/order/**
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10   # 每秒填 10 个令牌
                redis-rate-limiter.burstCapacity: 20   # 桶容量 20
                key-resolver: "#{@userKeyResolver}"

对应的 KeyResolver Bean,按用户 ID 限流:

@Bean
public KeyResolver userKeyResolver() {
    return exchange -> {
        String userId = exchange.getRequest().getHeaders().getFirst("X-User-Id");
        return Mono.just(userId != null ? userId : "anonymous");
    };
}

效果:每个用户每秒最多通过 10 个请求,允许突发到 20 个。超出的请求返回 429 Too Many Requests。

五、熔断降级

当下游服务响应过慢或频繁报错时,网关应该快速熔断,而不是让请求堆积。结合 Resilience4j:

spring:
  cloud:
    gateway:
      routes:
        - id: order-service
          uri: lb://order-service
          predicates:
            - Path=/api/order/**
          filters:
            - name: CircuitBreaker
              args:
                name: orderServiceCB
                fallbackUri: forward:/fallback/order
@RestController
public class FallbackController {
    @RequestMapping("/fallback/order")
    public ResponseEntity<Map<String, Object>> orderFallback() {
        return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).body(
                Map.of("code", 503, "message", "订单服务暂时不可用,请稍后重试")
        );
    }
}

六、生产部署与高可用

网关是所有请求的入口,本身必须高可用。生产环境通常部署 2 个以上网关实例,前面加 Nginx 负载均衡:

upstream gateway_cluster {
    server 10.0.0.11:8080 weight=1;
    server 10.0.0.12:8080 weight=1;
}

server {
    listen 80;
    location / {
        proxy_pass http://gateway_cluster;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

同时要注意:网关本身不要做重业务逻辑,它只是一个转发和过滤层。任何需要查数据库的操作都应该在下游服务完成,网关只做无状态的路由和过滤。

七、总结

Spring Cloud Gateway 是微服务架构的流量守门员。路由配置用 YAML 声明式搞定,鉴权和日志用全局过滤器统一处理,限流用 Redis 令牌桶保护后端,熔断降级防止故障扩散。记住一个原则:网关要轻、要快、要无状态,把复杂业务留给下游微服务。