一、核心概念
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 |
添加依赖 |
四、注意事项
- 线程模型:Gateway 基于 Netty,不能阻塞,避免在过滤器中使用
Thread.sleep()
或同步 IO。 - SpEL 表达式:
key-resolver: "#{@beanName}"
必须使用@
符号引用 Spring Bean。 - Redis 数据结构:限流使用 Redis 的
List
和String
存储令牌状态。 - 默认限流策略:
RedisRateLimiter
使用 令牌桶算法。 - 服务发现:
lb://service-name
依赖 Eureka/Nacos 等注册中心。
五、使用技巧
- 动态刷新路由:结合
Spring Cloud Config
或Nacos
实现路由热更新。 - 自定义过滤器:实现
GatewayFilter
或GlobalFilter
做签名校验、日志记录等。
@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());
}));
};
}
- 跨域配置:
spring:
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]':
allowedOrigins: "*"
allowedMethods: "*"
allowedHeaders: "*"
- 健康检查端点:访问
/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支撑不超载。”