在微服务架构中,API 网关作为系统的统一入口,承担着路由转发、负载均衡、认证鉴权、限流熔断等重要职责。Spring Cloud Gateway 作为 Spring Cloud 生态中的第二代网关,基于 Spring 5、Spring Boot 2 和 Project Reactor 构建,旨在取代 Netflix Zuul,提供更高效、更灵活的网关解决方案。
Spring Cloud Gateway 的设计围绕三个核心概念展开:
Client → Gateway Handler → Predicate Matching → Filter Chain → Target Service
↑ ↓
Route Locator Response Filters
Gateway 接收请求后,通过路由定位器查找匹配的路由,执行断言判断,通过后进入过滤器链处理,最终转发到目标服务。
通过 YAML 配置文件定义路由是最常用的方式:
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/users/**
- Method=GET,POST
filters:
- StripPrefix=1
- AddRequestHeader=X-Request-Source,Gateway
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/orders/**
- Query=version,v1
filters:
- CircuitBreaker=name=orderCircuitBreaker,fallbackUri=forward:/fallback/order
关键配置说明:
lb:// 表示使用负载均衡从服务注册中心获取实例StripPrefix 去掉路径前缀,如 /api/users/list → /users/listCircuitBreaker 集成熔断器,失败时转发到降级接口生产环境通常需要动态更新路由,可通过 RouteDefinitionRepository 实现:
@Component
public class RedisRouteDefinitionRepository implements RouteDefinitionRepository {
private final String ROUTE_KEY = "gateway:routes";
@Autowired
private StringRedisTemplate redisTemplate;
@Override
public Flux<RouteDefinition> getRouteDefinitions() {
List<RouteDefinition> routes = new ArrayList<>();
redisTemplate.opsForHash().values(ROUTE_KEY).forEach(route -> {
routes.add(JSON.parseObject(route.toString(), RouteDefinition.class));
});
return Flux.fromIterable(routes);
}
@Override
public Mono<Void> save(Mono<RouteDefinition> route) {
return route.flatMap(r -> {
redisTemplate.opsForHash().put(ROUTE_KEY, r.getId(),
JSON.toJSONString(r));
return Mono.empty();
});
}
// 发布路由刷新事件
public void publishRefreshEvent() {
applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));
}
}
通过 Redis 存储路由定义,结合 Spring 事件机制实现运行时热更新,无需重启网关。
当内置断言无法满足需求时,可自定义断言工厂:
@Component
public class TokenVersionRoutePredicateFactory extends
AbstractRoutePredicateFactory<TokenVersionRoutePredicateFactory.Config> {
public TokenVersionRoutePredicateFactory() {
super(Config.class);
}
@Override
public Predicate<ServerWebExchange> apply(Config config) {
return exchange -> {
String token = exchange.getRequest()
.getHeaders().getFirst("X-Token-Version");
return config.getVersion().equals(token);
};
}
@Data
public static class Config {
private String version;
}
}
// 使用方式
// predicates:
// - TokenVersion=v2
Spring Cloud Gateway 集成 RequestRateLimiter 过滤器,基于 Redis 实现令牌桶算法:
spring:
cloud:
gateway:
routes:
- id: rate_limited_route
uri: lb://user-service
predicates:
- Path=/api/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10 # 每秒填充10个令牌
redis-rate-limiter.burstCapacity: 20 # 桶容量20
redis-rate-limiter.requestedTokens: 1 # 每次消耗1个
key-resolver: "#{@userKeyResolver}" # 限流键解析器
@Bean
public KeyResolver userKeyResolver() {
// 按用户IP限流
return exchange -> Mono.just(
exchange.getRequest().getRemoteAddress().getAddress().getHostAddress()
);
}
@Bean
public KeyResolver apiKeyResolver() {
// 按API路径限流
return exchange -> Mono.just(
exchange.getRequest().getPath().value()
);
}
更复杂的限流策略可通过自定义过滤器实现:
@Component
public class CustomRateLimitFilter extends AbstractGatewayFilterFactory<CustomRateLimitFilter.Config> {
@Autowired
private ReactiveRedisTemplate<String, String> redisTemplate;
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
String key = getLimitKey(exchange, config);
return redisTemplate.opsForValue()
.increment(key)
.flatMap(count -> {
if (count == 1) {
// 首次访问,设置过期时间
return redisTemplate.expire(key, Duration.ofSeconds(config.getWindow()))
.thenReturn(count);
}
return Mono.just(count);
})
.flatMap(count -> {
if (count > config.getMaxRequests()) {
// 触发限流
exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
exchange.getResponse().getHeaders()
.add("X-RateLimit-Limit", String.valueOf(config.getMaxRequests()));
exchange.getResponse().getHeaders()
.add("X-RateLimit-Remaining", "0");
return exchange.getResponse().setComplete();
}
// 添加限流响应头
exchange.getResponse().getHeaders()
.add("X-RateLimit-Limit", String.valueOf(config.getMaxRequests()));
exchange.getResponse().getHeaders()
.add("X-RateLimit-Remaining",
String.valueOf(config.getMaxRequests() - count));
return chain.filter(exchange);
});
};
}
private String getLimitKey(ServerWebExchange exchange, Config config) {
String identifier = exchange.getRequest().getHeaders().getFirst("X-User-Id");
if (identifier == null) {
identifier = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
}
return String.format("rate:%s:%s", config.getType(), identifier);
}
@Data
public static class Config {
private int maxRequests = 100; // 窗口期内最大请求数
private int window = 60; // 时间窗口(秒)
private String type = "default"; // 限流类型
}
}
生产环境建议采用分级限流:
| 层级 | 策略 | 阈值 | 用途 |
|---|---|---|---|
| 全局 | 基于CPU/内存负载 | 动态调整 | 保护网关自身 |
| 服务 | 基于目标服务容量 | 服务注册元数据 | 保护下游服务 |
| 接口 | 基于API重要性 | 配置中心 | 核心业务保护 |
| 用户 | 基于用户等级 | 用户标签 | 差异化服务 |
@Component
public class RequestModifyFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 添加 traceId 用于全链路追踪
String traceId = UUID.randomUUID().toString().replace("-", "");
ServerHttpRequest request = exchange.getRequest().mutate()
.header("X-Trace-Id", traceId)
.header("X-Request-Time", String.valueOf(System.currentTimeMillis()))
.build();
return chain.filter(exchange.mutate().request(request).build())
.then(Mono.fromRunnable(() -> {
// 响应后处理
Long startTime = Long.parseLong(
exchange.getRequest().getHeaders().getFirst("X-Request-Time"));
long duration = System.currentTimeMillis() - startTime;
log.info("TraceId: {}, Duration: {}ms", traceId, duration);
}));
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE; // 最先执行
}
}
@Component
public class GrayReleaseFilter extends AbstractGatewayFilterFactory<Config> {
@Autowired
private GrayReleaseService grayService;
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
String userId = exchange.getRequest().getHeaders().getFirst("X-User-Id");
// 判断用户是否在灰度名单
if (grayService.isGrayUser(userId, config.getService())) {
// 修改路由目标到灰度版本
ServerHttpRequest request = exchange.getRequest().mutate()
.header("X-Gray-Version", "v2")
.build();
// 通过元数据选择灰度实例
exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR,
URI.create("lb://" + config.getService() + "-gray"));
return chain.filter(exchange.mutate().request(request).build());
}
return chain.filter(exchange);
};
}
}
Spring Cloud Gateway 作为响应式网关的代表,通过灵活的路由配置、丰富的过滤器机制和强大的限流能力,为微服务架构提供了可靠的入口保护。在实际应用中,建议结合配置中心实现动态路由管理,采用多级限流策略保障系统稳定性,并通过全链路追踪和监控指标持续优化网关性能。
随着云原生技术的发展,Spring Cloud Gateway 与 Kubernetes Ingress、Service Mesh 的集成将成为新的探索方向,为微服务治理提供更加完善的解决方案。