Spring Cloud Gateway 网关与限流实战
在微服务架构里,API 网关是所有外部请求的统一入口。Spring Cloud Gateway 基于 Spring Boot 3 和 WebFlux 构建,提供路由转发、过滤器链、限流熔断等核心能力。本文从路由规则配置讲起,深入全局过滤器与自定义过滤器,最后覆盖 Redis 限流与生产部署的完整方案。
一、网关在微服务中的位置
没有网关的时候,前端需要直接调用每个微服务的地址,还要自己处理认证、跨域、限流。有了网关之后,所有请求先到网关,由网关决定路由到哪个服务,并统一处理横切逻辑。
网关的核心职责包括:路由转发(把 /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 令牌桶保护后端,熔断降级防止故障扩散。记住一个原则:网关要轻、要快、要无状态,把复杂业务留给下游微服务。