Gateway 服务网关
定位说明
Spring Cloud Gateway 是基于 Spring WebFlux 的 API 网关,作为微服务架构的统一入口,承担路由转发、鉴权、限流、日志等横切关注点。Spring Cloud Alibaba 生态中,Gateway 与 Nacos 深度集成,实现动态路由、从注册中心自动发现服务等能力。
与 Netflix Zuul 的区别:Gateway 基于 Reactor 响应式编程(非阻塞 I/O),性能远优于基于 Servlet 的 Zuul 1.x;Zuul 2.x 已停更,Gateway 是 Spring 官方推荐的唯一网关方案。
前置知识:读者应掌握 Spring Boot 基础、Nacos 注册中心。
核心概念速览
Gateway 的核心三要素:
| 要素 | 说明 | 类比 |
|---|---|---|
| Route(路由) | 网关的基本构建块,包含 ID、目标 URI、断言集合、过滤器集合 | Nginx 的 location |
| Predicate(断言) | 匹配 HTTP 请求的条件(路径、Header、参数等) | Nginx 的 if 判断 |
| Filter(过滤器) | 对请求/响应进行修改处理的拦截器 | Servlet Filter |
环境准备
Maven 依赖
<dependencies>
<!-- Spring Cloud Gateway -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- Nacos 注册中心(用于动态路由和服务发现) -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- Gateway 集成 Nacos(lb:// 协议支持) -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
</dependencies>
注意:Gateway 基于 WebFlux,不能同时引入
spring-boot-starter-web(Servlet 容器),否则启动报错。
基本配置文件
server:
port: 8080
spring:
application:
name: api-gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
gateway:
discovery:
locator:
enabled: true # 自动从 Nacos 发现服务并生成路由
lower-case-service-id: true # 服务名转为小写
routes:
- id: user-service # 路由 ID,唯一
uri: lb://user-service # lb:// 表示从 Nacos 负载均衡获取地址
predicates:
- Path=/api/users/** # 匹配 /api/users/xxx 请求
路由配置详解
一、基础路由方式
Gateway 支持三种路由配置方式:
| 方式 | 说明 | 灵活性 |
|---|---|---|
| 自动发现路由 | discovery.locator.enabled=true,自动将 Nacos 中的服务生成路由 | 低,路由规则固定为 /{service-name}/** |
| YAML 静态配置 | 在 application.yml 中显式定义 routes | 中,需重启应用 |
| 编码动态路由 | 用代码定义 RouteLocator,可从数据库加载 | 高,支持动态更新 |
二、YAML 静态路由示例
spring:
cloud:
gateway:
routes:
# 用户服务
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/users/**
filters:
- StripPrefix=1 # 转发前去掉 /api 前缀
# 订单服务(按时间匹配)
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/orders/**
- After=2026-01-01T00:00:00+08:00 # 仅在指定时间后生效
filters:
- StripPrefix=1
# 商品服务(按 Header 匹配)
- id: product-service
uri: lb://product-service
predicates:
- Path=/api/products/**
- Header=X-API-Version, 2.0 # 仅匹配特定 Header 的请求
filters:
- StripPrefix=1
三、编码动态路由
@Configuration
public class GatewayRouteConfig {
@Bean
public RouteLocator customRoutes(RouteLocatorBuilder builder) {
return builder.routes()
.route("baidu-route", r -> r
.path("/baidu/**")
.uri("https://www.baidu.com"))
.route("user-route", r -> r
.path("/api/users/**")
.filters(f -> f.stripPrefix(1)
.addRequestHeader("X-Gateway", "true"))
.uri("lb://user-service"))
.build();
}
}
Predicate(断言)速查
| 断言工厂 | 说明 | 示例 |
|---|---|---|
Path | 按路径匹配 | Path=/api/users/** |
Method | 按 HTTP 方法匹配 | Method=GET,POST |
Header | 按请求头匹配 | Header=X-Token, .+ |
Query | 按查询参数匹配 | Query=version, v2 |
Host | 按 Host 头匹配 | Host=**.example.com |
After | 在指定时间后匹配 | After=2026-01-01T00:00:00+08:00 |
Before | 在指定时间前匹配 | Before=2027-01-01T00:00:00+08:00 |
Between | 在指定时间段内匹配 | Between=... |
Cookie | 按 Cookie 匹配 | Cookie=sessionId, .+ |
RemoteAddr | 按客户端 IP 匹配 | RemoteAddr=192.168.1.0/24 |
Weight | 按权重路由(灰度发布) | Weight=group1, 80 |
Filter(过滤器)速查
内置过滤器
| 过滤器工厂 | 说明 | 示例 |
|---|---|---|
StripPrefix | 去除路径前缀 | StripPrefix=1(去掉 1 段) |
AddRequestHeader | 添加请求头 | AddRequestHeader=X-Source, gateway |
AddRequestParameter | 添加请求参数 | AddRequestParameter=source, gateway |
RemoveRequestHeader | 移除请求头 | RemoveRequestHeader=X-Secret |
AddResponseHeader | 添加响应头 | AddResponseHeader=X-Response-Time, %s |
PrefixPath | 添加路径前缀 | PrefixPath=/api |
RewritePath | 正则路径重写 | RewritePath=/api/(?<seg>.*), /$\{seg} |
SetStatus | 设置响应状态码 | SetStatus=401 |
Retry | 重试机制 | Retry=3 |
自定义全局过滤器
@Component
@Slf4j
public class RequestLoggingFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
String path = request.getURI().getPath();
String method = request.getMethodValue();
log.info("[Gateway] {} {}", method, path);
long start = System.currentTimeMillis();
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
long duration = System.currentTimeMillis() - start;
log.info("[Gateway] {} {} — {}ms",
method, path, duration);
}));
}
@Override
public int getOrder() {
return -1; // 最先执行
}
}
与 Nacos 深度集成
一、动态路由(无需重启)
Gateway 默认将路由配置写在 YAML 中,修改需重启。配合 Nacos Config 可实现动态路由更新:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
spring:
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848
file-extension: yaml
shared-configs:
- data-id: gateway-routes.yaml
group: DEFAULT_GROUP
refresh: true # 支持动态刷新
在 Nacos 控制台中修改 gateway-routes.yaml,Gateway 会监听到变更并自动更新路由表。
二、lb:// 协议与服务发现
lb://service-name 是 Gateway 内置的负载均衡协议,底层调用 Spring Cloud LoadBalancer 从 Nacos 获取实例列表并选择。无需手动配置目标 IP:Port。
限流(Rate Limiting)
Gateway 内置基于 Redis + 令牌桶算法 的限流器。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
@Configuration
public class RateLimitConfig {
@Bean
public KeyResolver userKeyResolver() {
// 按请求路径限流
return exchange -> Mono.just(
exchange.getRequest().getURI().getPath());
}
@Bean
public KeyResolver ipKeyResolver() {
// 按客户端 IP 限流
return exchange -> {
String ip = exchange.getRequest().getRemoteAddress()
.getAddress().getHostAddress();
return Mono.just(ip);
};
}
}
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/users/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10 # 每秒允许 10 个请求
redis-rate-limiter.burstCapacity: 20 # 突发容量 20
key-resolver: "#{@ipKeyResolver}" # 按 IP 限流
跨域(CORS)配置
spring:
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]':
allowed-origins: "https://www.example.com"
allowed-methods: GET, POST, PUT, DELETE
allowed-headers: "*"
allow-credentials: true
max-age: 3600
或用 Java 配置:
@Configuration
public class CorsConfig implements WebFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
ServerHttpResponse response = exchange.getResponse();
response.getHeaders().add("Access-Control-Allow-Origin", "*");
response.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
response.getHeaders().add("Access-Control-Allow-Headers", "*");
return chain.filter(exchange);
}
}
生产实践
一、架构最佳实践
┌──────────────────┐
│ Nginx / SLB │ (公网入口)
└────────┬─────────┘
│
┌────────▼─────────┐
│ Spring Cloud │ (统一网关层)
│ Gateway │
└──┬──────┬──────┬─┘
│ │ │
┌─────────▼─┐ ┌──▼───┐ ┌▼─────────┐
│ User Svc │ │Order │ │Product Svc│ (微服务层)
└───────────┘ │Svc │ └───────────┘
└──────┘
二、常见问题与解决方案
| 问题 | 原因 | 解决方案 |
|---|---|---|
| Gateway 启动报 "No qualifying bean of type 'org.springframework.web.reactive.DispatcherHandler'" | 同时引入了 spring-boot-starter-web | 移除 web starter,Gateway 基于 WebFlux |
| 路由不生效 | Predicate 条件未命中 | 开启 debug 日志:logging.level.org.springframework.cloud.gateway=DEBUG |
| 504 Gateway Timeout | 后端服务响应超时 | 增大 connect-timeout / response-timeout |
| 大文件上传失败 | 默认 body 大小限制 | 配置 spring.cloud.gateway.routes[].filters[].name=RequestSize |
面试考点
1. Gateway 的工作流程?
请求 → Gateway Handler Mapping(匹配路由)→ Web Handler(执行过滤器链)→ 转发到后端服务 → 响应经过滤器链回传。过滤器链按 Ordered 接口排序。
2. Gateway 和 Zuul 的区别?
| 维度 | Gateway | Zuul 1.x |
|---|---|---|
| 编程模型 | 非阻塞(Reactor/WebFlux) | 阻塞(Servlet 2.5) |
| 性能 | 高(事件驱动) | 较低(线程池 + 连接池) |
| 维护状态 | Spring 官方活跃维护 | Netflix 停更 |
| 长连接支持 | WebSocket 原生支持 | 需要额外配置 |
| 动态路由 | 支持 | 不支持 |
3. lb:// 协议是如何工作的?
lb://service-name 是 Gateway 内置的负载均衡协议,其实现依赖 Spring Cloud LoadBalancer。Gateway 从 Nacos 发现目标服务的所有实例,通过 LoadBalancer 选择一个实例,替换 lb:// 为实际 http://IP:PORT。
4. Gateway 如何实现灰度发布?
两种方式:
- Weight 断言:
- Weight=group1, 80和- Weight=group2, 20,按权重将流量分发到不同的 uri。 - 结合 Nacos 元数据:在 Nacos 中为实例标记版本信息,自定义 LoadBalancer 规则按元数据路由。
5. 如何实现 Gateway 的高可用?
- Gateway 本身是无状态应用,通过部署多个实例 + Nginx/SLB 前置实现水平扩展。
- 注册到 Nacos 后,上游 Nginx 通过健康检查发现异常 Gateway 节点并剔除。
- 限流依赖的 Redis 建议使用哨兵/集群模式保证高可用。
参考资源:
- Spring Cloud Gateway 官方文档:https://docs.spring.io/spring-cloud-gateway
- Gateway + Nacos 集成:https://sca.aliyun.com