Spring Cloud Gateway 现代化 API 网关
导学
飞翔科技 API 网关选型会议上,白歌在白板上画了一张对比表:
| 维度 | Zuul 1.x | Gateway |
|---|---|---|
| 线程模型 | Servlet 阻塞 | Reactor 非阻塞 |
| 内存占用 | 每个连接 1MB+ 线程栈 | 少量 Event Loop 线程 |
| WebSocket | 不支持 | 原生支持 |
"Gateway 不仅是 Zuul 的替代品,更是全新一代的 API 网关架构。"白歌说,"它是 Spring 生态中第一个完全响应式的网关。"
定位与问题场景
Spring Cloud Gateway 基于 Spring WebFlux 和 Project Reactor,提供:
- 路由(Route):将请求转发到目标服务
- 断言(Predicate):匹配请求条件(路径、Header、参数等)
- 过滤器(Filter):对请求/响应进行拦截处理
三大核心概念:
Gateway 核心原理
基于 WebFlux 的非阻塞处理
关键区别:整个请求生命周期中,没有线程被阻塞等待 I/O。当等待后端响应时,Event Loop 线程可以处理其他请求。
Route Predicate 工厂
Gateway 内置 11 种 Predicate 工厂,以下是常用类型:
| Predicate | 示例 | 说明 |
|---|---|---|
| Path | - Path=/api/order/** | 路径匹配 |
| Header | - Header=X-version, v2 | 请求头匹配 |
| Method | - Method=GET,POST | HTTP 方法 |
| Query | - Query=category, electronics | Query 参数 |
| Host | - Host=**.feixiang.com | Host 域名 |
| Cookie | - Cookie=sessionId, .+ | Cookie 匹配 |
| Weight | - Weight=group1, 80 | 按权重分流(灰度发布) |
GatewayFilter 工厂
| Filter | 示例 | 说明 |
|---|---|---|
| AddRequestHeader | AddRequestHeader=X-User-Id, 123 | 添加请求头 |
| AddResponseHeader | AddResponseHeader=X-Response-Time, 100ms | 添加响应头 |
| StripPrefix | StripPrefix=1 | 去掉一级路径前缀 |
| PrefixPath | PrefixPath=/api | 添加路径前缀 |
| RequestRateLimiter | 基于 Redis 的令牌桶限流 | 限流 |
| CircuitBreaker | 集成 Resilience4j 熔断 | 网关层熔断 |
| Retry | Retry=3 | 重试 |
完整示例:飞翔科技 Gateway 网关
场景描述
上线 Gateway 替代 Zuul,实现路由转发、统一认证、限流和灰度发布。
操作前后对比:
| 维度 | 迁移前(Zuul) | 迁移后(Gateway) |
|---|---|---|
| 请求处理 | 阻塞,每请求一线程 | 非阻塞,Event Loop |
| 灰度发布 | 需自定义 Filter | Weight Predicate 原生支持 |
| 限流 | 需自定义 Filter | RequestRateLimiter 开箱即用 |
步骤一:依赖引入
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- Gateway 是 WebFlux 项目,不能引入 spring-boot-starter-web -->
步骤二:基础路由配置(Java DSL)
@Configuration
public class GatewayConfig {
@Bean
public RouteLocator customRoutes(RouteLocatorBuilder builder) {
return builder.routes()
// 路由 1:订单服务
.route("order-service-route", r -> r
.path("/api/order/**")
.filters(f -> f
.stripPrefix(1)
.addRequestHeader("X-Gateway", "feixiang-gateway")
)
.uri("lb://FEIXIANG-ORDER-SERVICE")
)
// 路由 2:库存服务
.route("inventory-service-route", r -> r
.path("/api/inventory/**")
.filters(f -> f.stripPrefix(1))
.uri("lb://FEIXIANG-INVENTORY-SERVICE")
)
// 路由 3:灰度发布(80% 流量到 v1,20% 到 v2)
.route("order-v1", r -> r
.path("/api/order/**")
.and().weight("order-group", 80)
.uri("lb://FEIXIANG-ORDER-SERVICE-V1")
)
.route("order-v2", r -> r
.path("/api/order/**")
.and().weight("order-group", 20)
.uri("lb://FEIXIANG-ORDER-SERVICE-V2")
)
.build();
}
}
步骤三:YAML 路由配置
spring:
cloud:
gateway:
routes:
# 订单服务路由
- id: order-service
uri: lb://FEIXIANG-ORDER-SERVICE
predicates:
- Path=/api/order/**
filters:
- StripPrefix=1
- AddRequestHeader=X-Gateway, feixiang-gateway
# 库存服务路由
- id: inventory-service
uri: lb://FEIXIANG-INVENTORY-SERVICE
predicates:
- Path=/api/inventory/**
filters:
- StripPrefix=1
# 灰度发布
- id: order-v1
uri: lb://FEIXIANG-ORDER-SERVICE
predicates:
- Path=/api/order/**
- Weight=order-group, 80
- id: order-v2
uri: lb://FEIXIANG-ORDER-SERVICE-V2
predicates:
- Path=/api/order/**
- Weight=order-group, 20
步骤四:全局过滤器——统一认证
@Component
@Slf4j
public class AuthGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
String path = request.getURI().getPath();
// 放行登录接口
if (path.startsWith("/api/auth/login")) {
return chain.filter(exchange);
}
// 校验 Token
String token = request.getHeaders().getFirst("Authorization");
if (token == null || !token.startsWith("Bearer ")) {
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.UNAUTHORIZED);
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
byte[] body = "{\"code\":401,\"message\":\"未授权\"}".getBytes();
return response.writeWith(
Mono.just(response.bufferFactory().wrap(body))
);
}
// 传递用户信息到下游
ServerHttpRequest modifiedRequest = request.mutate()
.header("X-User-Id", extractUserId(token))
.build();
return chain.filter(exchange.mutate().request(modifiedRequest).build());
}
@Override
public int getOrder() {
return -1; // 高优先级
}
}
步骤五:Redis 限流
spring:
cloud:
gateway:
routes:
- id: order-service
uri: lb://FEIXIANG-ORDER-SERVICE
predicates:
- Path=/api/order/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter:
replenishRate: 10 # 每秒生成令牌数
burstCapacity: 20 # 令牌桶容量
key-resolver: "#{@ipKeyResolver}"
data:
redis:
host: localhost
port: 6379
@Configuration
public class RateLimiterConfig {
@Bean
public KeyResolver ipKeyResolver() {
return exchange -> Mono.just(
exchange.getRequest().getRemoteAddress().getAddress().getHostAddress()
);
}
}
易错场景
1. 引入 spring-boot-starter-web 导致启动失败
Gateway 基于 WebFlux,与 Spring MVC(Servlet)互斥。项目不能同时引入 spring-boot-starter-web 和 spring-cloud-starter-gateway。
报错:Spring MVC found on classpath, which is incompatible with Spring Cloud Gateway
2. lb:// 前缀缺失导致不经过 LoadBalancer
# ❌ 错误:直接写 URL,不走负载均衡和服务发现
uri: http://localhost:8080
# ✅ 正确:lb:// 前缀,走 LoadBalancer
uri: lb://FEIXIANG-ORDER-SERVICE
3. Weight Predicate 未正确配置 group
# ❌ 错误:只有一个路由配了权重,另一个没配,权重路由不生效
# ✅ 正确:同一 group 的多个路由权重和应为 100
- Weight=order-group, 80
- Weight=order-group, 20
4. 过滤器顺序问题
Gateway 中 order 越小优先级越高。认证过滤器应放在最前面(如 order=-1),跨域过滤器也应高优先级。
面试考点
Gateway 和 Zuul 1.x 的核心区别?
Gateway 基于 WebFlux/Reactor 非阻塞架构,使用 Netty 作为底层通信组件,少量 Event Loop 线程处理大量并发;Zuul 1.x 基于 Servlet 阻塞模型,每个请求占用一个线程。Gateway 支持 WebSocket 长连接,Zuul 1.x 不支持。Gateway 的 Predicate(断言)+ Filter(过滤器)机制比 ZuulFilter 更灵活。
Gateway 路由匹配的过程?
RoutePredicateHandlerMapping遍历所有 Route 定义- 对每个 Route,逐一评估其 Predicate 组合(AND 关系)
- 找到第一个完全匹配的 Route,返回给
FilteringWebHandlerFilteringWebHandler加载该 Route 的 GatewayFilter 和所有 GlobalFilter 组成过滤器链- 按 order 排序后依次执行,最终转发到目标 URI
Gateway 如何实现限流?
内置
RequestRateLimiterGatewayFilter,基于 Redis + 令牌桶算法。replenishRate控制令牌生成速率,burstCapacity控制桶容量(允许突发流量)。通过KeyResolver定义限流维度:IP、用户 ID、接口路径等。
Gateway 如何实现灰度发布?
WeightPredicate:将流量按权重分配到不同版本的微服务。- id: v1 predicates: - Path=/api/** - Weight=group1, 80 uri: lb://service-v1 - id: v2 predicates: - Path=/api/** - Weight=group1, 20 uri: lb://service-v2
小结
Spring Cloud Gateway 以响应式架构重新定义了 API 网关,在性能(非阻塞 I/O)、功能(Predicate + Filter)、可扩展性(自定义 GlobalFilter)方面全面超越 Zuul 1.x。内置的限流、熔断、灰度发布能力让网关成为微服务架构的真正"守门人"。下一章我们转向异步通信——Spring Cloud Stream 消息驱动。