人人都会AI编程

16.5 API 网关:Spring Cloud Gateway 路由、断言、过滤器

更新时间:2026-07-10

在微服务架构中,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-servicelb 前缀表示启用客户端负载均衡,需配合 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 在内网地址段的请求。

时间与权重断言:另外还有 BeforeAfterBetween 等基于时间的断言,可用于定时生效的路由或活动期间的特殊转发;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 执行负载均衡,替换为真实的服务实例地址。
  • NettyRoutingFilterWebsocketRoutingFilter:实际转发 HTTP 和 WebSocket 请求。
  • ReactiveLoadBalancerClientFilter:响应式负载均衡。
  • GatewayMetricsFilter:收集网关性能指标。

自定义全局过滤器只需实现 GlobalFilterOrdered 接口,并注册为 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 网关层。