在微服务架构中,API 网关是整个系统的统一入口。它承担着请求路由、协议转换、安全认证、流量控制、日志监控等职责,是外部客户端与内部服务之间的一层智能屏障。Spring Cloud Gateway 是 Spring 官方推出的网关解决方案,基于 Spring WebFlux 的响应式编程模型构建,天然支持非阻塞 I/O,具备高性能和低资源消耗的特点。
16.5.1 为什么选择 Spring Cloud Gateway
早期 Spring Cloud 体系中使用 Netflix Zuul 作为网关,但 Zuul 1.x 基于阻塞式 Servlet 架构,面对高并发长连接场景时存在性能瓶颈。Spring Cloud Gateway 在设计上做了根本性升级:
- 异步非阻塞:底层使用 Reactor Netty,线程资源利用率极高,适合 I/O 密集型场景。
- 响应式编程:与 Spring WebFlux 一脉相承,路由匹配、请求转发、过滤器链全链路异步化。
- 灵活的谓词与过滤器体系:路由规则可基于请求路径、Header、参数等多种条件组合,过滤器支持请求修改、响应改写、限流熔断等丰富功能。
- 与 Spring 生态深度整合:可直接集成 Spring Cloud 的服务发现(Nacos、Consul)、配置中心、断路器(Resilience4j)等组件。
从 Spring Cloud 2020.0 版本开始,Spring Cloud Gateway 已成为官方推荐的网关实现,替代了处于维护模式的 Netflix Zuul。
16.5.2 路由(Route):网关的核心单元
路由是网关最基本的构建块。一个路由包含以下要素:
- ID:路由的唯一标识。
- 目标 URI:请求最终被转发到的目标地址。
- 断言集合:一组匹配规则,决定哪些请求由该路由处理。
- 过滤器集合:对请求或响应进行加工处理的一系列拦截器。
在 Spring Cloud Gateway 中,路由可以通过配置文件(application.yml)或 Java 编码方式进行定义。实际生产中以配置文件方式为主,简洁且易于版本管理。
一个典型的配置文件示例:
spring:
cloud:
gateway:
routes:
- id: user-service-route
uri: lb://user-service # 使用负载均衡方式转发到微服务
predicates:
- Path=/api/users/** # 路径匹配断言
filters:
- StripPrefix=1 # 去除路径前缀的过滤器
- id: order-service-route
uri: http://localhost:8082
predicates:
- Path=/api/orders/**
- Header=X-Request-Source, mobile # 要求请求头满足特定值
filters:
- AddRequestHeader=X-Forwarded-For, gateway
以上配置定义了两条路由规则。当请求路径以 /api/users/ 开头时,网关会将其转发到 lb://user-service(lb 前缀表示启用客户端负载均衡,需配合 Nacos 等服务注册中心使用),同时剥离 /api 前缀,使下游服务收到的路径变为 /users/**。第二条路由则在路径匹配的基础上额外要求请求头 X-Request-Source 的值为 mobile,才将请求转发到指定的 URL。
16.5.3 断言(Predicate):定义路由的匹配条件
断言的作用是为请求选择匹配的路由。Spring Cloud Gateway 内置了十几种断言工厂,通过特定的命名规则和参数进行配置。常用断言及其作用如下:
| 断言工厂 | 配置示例 | 说明 |
|---|---|---|
| Path | - Path=/api/product/** | 基于请求路径的 Ant 风格匹配。 |
| Header | - Header=X-Request-Id, \d+ | 请求头必须存在且值匹配正则表达式。 |
| Method | - Method=GET,POST | 限制 HTTP 方法。 |
| Query | - Query=name, kitty | 请求参数必须包含指定键,值可选匹配正则。 |
| Cookie | - Cookie=sessionId, [a-z]+ | 基于 Cookie 名称和值的正则匹配。 |
| Host | - Host=.example.com, .other.com | 根据请求的 Host 头匹配(多域名路由)。 |
| RemoteAddr | - RemoteAddr=192.168.1.0/24 | 根据客户端 IP 地址段匹配。 |
| Weight | - Weight=group1, 8(配合另一条权重 2 的路由) | 同一组内按权重分配流量,常用于灰度发布。 |
组合使用:同一个路由中可以配置多个断言,它们之间是“逻辑与”的关系,只有全部满足时路由才会生效。断言的组合可以灵活构建出丰富的路由策略。例如:
predicates:
- Path=/api/vip/**
- Header=X-VIP-Token
- RemoteAddr=10.0.0.0/8
此路由只会匹配路径以 /api/vip/ 开头、携带 X-VIP-Token 头、且客户端 IP 在内网地址段的请求。
时间与权重断言:另外还有 Before、After、Between 等基于时间的断言,可用于定时生效的路由或活动期间的特殊转发;Weight 断言可实现流量比例分配,适合蓝绿部署和金丝雀发布。
16.5.4 过滤器(Filter):请求与响应的加工管道
过滤器是网关对请求和响应进行处理的组件,它们组成了责任链式的处理管道。Spring Cloud Gateway 的过滤器分为两类:
1. GatewayFilter(网关过滤器)
应用于特定路由上的过滤器,由 filters 配置项指定。内置了数十种实用过滤器:
- 请求修改类
AddRequestHeader/AddRequestParameter:添加请求头或参数。RemoveRequestHeader/RemoveRequestParameter:移除请求头或参数。SetRequestHeader:设置或替换请求头。RewritePath:重写请求路径(支持正则捕获组)。StripPrefix:剥离路径前缀(数字表示去除的段数)。
- 响应修改类
AddResponseHeader/RemoveResponseHeader/SetResponseHeader:增删改响应头。RewriteResponseHeader:基于正则重写响应头。DedupeResponseHeader:去除重复的响应头。
- 功能增强类
RequestRateLimiter:基于令牌桶算法的请求限流,需配合RedisRateLimiter。Retry:为下游服务调用配置重试策略(次数、状态码、方法等)。CircuitBreaker:集成 Resilience4j 实现断路器功能。FallbackHeaders:转发断路器异常时的回退头信息。SaveSession:强制保存 WebSession 到 Session 存储。PrefixPath:为路径增加统一前缀。SetStatus:直接设置响应状态码。
2. GlobalFilter(全局过滤器)
作用于所有路由的过滤器,无需配置,自动生效。它们实现了跨路由的通用逻辑,例如:
ForwardRoutingFilter:处理forward类型的路由。LoadBalancerClientFilter:为lb://前缀的 URI 执行负载均衡,替换为真实的服务实例地址。NettyRoutingFilter、WebsocketRoutingFilter:实际转发 HTTP 和 WebSocket 请求。ReactiveLoadBalancerClientFilter:响应式负载均衡。GatewayMetricsFilter:收集网关性能指标。
自定义全局过滤器只需实现 GlobalFilter 和 Ordered 接口,并注册为 Spring Bean 即可。
16.5.5 实战:构建一个可用的网关
下面通过一个完整的配置示例,展示如何在项目中引入 Spring Cloud Gateway 并实现常见功能。
步骤一:引入依赖
在 Spring Boot 项目中添加 gateway starter,同时排除与 WebMVC 冲突的 spring-boot-starter-web(Gateway 基于 WebFlux)。
<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>
步骤二:基本路由配置
server:
port: 9000
spring:
application:
name: api-gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
gateway:
discovery:
locator:
enabled: true # 开启根据服务名自动创建路由
lower-case-service-id: true
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/user/**
filters:
- StripPrefix=1
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/order/**
filters:
- StripPrefix=1
开启 spring.cloud.gateway.discovery.locator.enabled 后,网关会自动为注册中心里的每个服务创建默认路由,规则为 /${serviceName}/** 转发到对应的 lb://serviceName。但显式定义路由仍是推荐做法,便于精确控制断言和过滤器。
步骤三:添加限流与熔断
引入 spring-boot-starter-data-redis-reactive 依赖,用于限流器的计数器存储。
spring:
redis:
host: 127.0.0.1
port: 6379
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/user/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10 # 每秒钟允许10个请求
redis-rate-limiter.burstCapacity: 20 # 突发容量20
key-resolver: "#{@remoteAddrKeyResolver}"
- name: CircuitBreaker
args:
name: userServiceCB
fallbackUri: forward:/fallback/user
key-resolver 需要定义一个 KeyResolver Bean,例如基于请求 IP 限流:
@Bean
KeyResolver remoteAddrKeyResolver() {
return exchange ->
Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
}
当触发限流时,网关会返回 429 Too Many Requests;熔断发生时则转发到指定的回退地址。
步骤四:自定义全局过滤器(如鉴权)
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
String token = request.getHeaders().getFirst("Authorization");
if (token == null || !token.startsWith("Bearer ")) {
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
// 可调用认证中心校验 token,解析出用户信息写入请求头
ServerHttpRequest newRequest = request.mutate()
.header("X-User-Id", "123456")
.build();
return chain.filter(exchange.mutate().request(newRequest).build());
}
@Override
public int getOrder() {
return -100; // 优先级高,确保在转发之前执行
}
}
全局过滤器可以对所有路由进行统一的身份认证、参数校验等,是网关安全拦截的理想位置。
16.5.6 注意事项与最佳实践
- 路径前缀处理:在统一为后端服务添加
/api前缀后,务必配合StripPrefix过滤器移除前缀,避免下游服务收到意料之外的路径。 - 超时配置:网关与下游服务之间的调用超时必须合理设置,避免长时间阻塞线程,可在
spring.cloud.gateway.httpclient下配置连接超时和响应超时。 - 与 WebFlux 的兼容性:网关依赖 WebFlux 环境,不能同时引入
spring-boot-starter-web(会冲突)。如果项目中已有 MVC 应用,需将网关抽离为独立服务。 - 动态路由:配合配置中心(如 Nacos Config),可动态刷新路由配置而无需重启网关实例。
- 监控与日志:启用
GatewayMetricsFilter并集成 Micrometer + Prometheus,可监控网关的请求量、延迟、状态码分布等关键指标。
Spring Cloud Gateway 以其优雅的断言-过滤器架构和出色的异步性能,成为构建微服务网关的首选方案。掌握了路由定义、断言组合和过滤器链的使用,就能高效地搭建起功能完备、灵活可靠的 API 网关层。