侧边栏壁纸
博主头像
牧云

怀璧慎显,博识谨言。

  • 累计撰写 180 篇文章
  • 累计创建 18 个标签
  • 累计收到 8 条评论

目 录CONTENT

文章目录

Spring Cloud Gateway 全栈指南:核心原理、内置组件详解与集群化实战

秋之牧云
2026-05-09 / 0 评论 / 0 点赞 / 1 阅读 / 0 字

在微服务架构中,API 网关是系统的“守门员”,负责路由转发、鉴权、限流和监控等关键功能。Spring Cloud Gateway (SCG) 作为 Spring 官方推出的第二代网关,基于 Spring WebFlux 和 Reactor 模型构建,凭借非阻塞的高性能特性,已逐渐取代 Netflix Zuul 成为主流选择。

本文将深入解析 SCG 的核心概念,详细盘点其强大的内置断言与过滤器,并通过代码示例展示如何扩展自定义逻辑,最后探讨生产环境下的集群化部署方案。

1. 核心架构与工作原理

Spring Cloud Gateway 的工作流由三个核心概念组成 :

  1. 路由(Route):网关的基本构建块,由 ID、目标 URI、断言集合(Predicates)和过滤器集合(Filters)组成。
  2. 断言(Predicate):用于匹配 HTTP 请求的条件(如路径、Header、时间)。只有当所有断言为真时,请求才会被路由到指定服务。
  3. 过滤器(Filter):在请求发送之前或响应返回之后进行修改。分为局部过滤器(针对特定路由)和全局过滤器(针对所有路由)。

2. 内置组件全景图

SCG 提供了丰富的内置组件,无需编写代码即可通过配置实现大部分网关功能。

2.1 内置断言工厂 (Route Predicate Factories)

断言决定了“哪些请求可以被路由”。以下是常用的内置断言 :

断言名称描述配置示例
Path基于请求路径匹配,支持 Ant 风格Path=/api/**
Method基于 HTTP 方法匹配Method=GET,POST
Query基于查询参数匹配Query=name, zhang.* (正则)
Header基于请求头匹配Header=X-Request-Id, \d+
Cookie基于 Cookie 匹配Cookie=chocolate, ch.p
Host基于 Host 头匹配Host=**.example.com
RemoteAddr基于客户端 IP 匹配RemoteAddr=192.168.1.1/24
After/Before/Between基于时间匹配After=2023-01-01T00:00:00+08:00
Weight基于权重分组,用于灰度发布Weight=group1, 8 (80%流量)

配置示例:

spring:
  cloud:
    gateway:
      routes:
        - id: path_route
          uri: https://example.org
          predicates:
            - Path=/red/{segment} # 匹配 /red/1, /red/blue 等
            - Method=GET
            - Query=color, red # 且查询参数 color 必须为 red

2.2 内置过滤器工厂 (Gateway Filter Factories)

过滤器负责“如何处理请求和响应”。常用的内置过滤器包括 :

过滤器名称功能描述配置示例
AddRequestParameter添加请求参数AddRequestParameter=color, blue
AddRequestHeader添加请求头AddRequestHeader=X-Request-Red, Blue
AddResponseHeader添加响应头AddResponseHeader=X-Response-Red, Blue
StripPrefix去除路径前缀StripPrefix=1 (/api/user -> /user)
RewritePath重写路径正则RewritePath=/red/(?<segment>.*), /$\{segment}
SetStatus设置响应状态码SetStatus=401
Retry失败重试Retry=retries=3, statuses=BAD_GATEWAY
RequestRateLimiter限流(需配合 Redis)见下文集群部分
RedirectTo重定向RedirectTo=302, https://acme.org

配置示例:

filters:
  - StripPrefix=1 # 去除第一层路径
  - AddRequestHeader=X-Request-Source, Gateway
  - Retry=retries=3, statuses=503

3. 进阶实战:自定义断言与过滤器

当内置组件无法满足需求时,我们可以轻松扩展。

3.1 自定义断言:基于时间的灰度匹配

假设我们需要一个断言,仅允许在特定时间段内访问某服务。

import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import java.time.LocalDateTime;
import java.util.function.Predicate;

/**
 * 自定义断言工厂:TimeRangeRoutePredicateFactory
 * 命名规范:类名必须以 RoutePredicateFactory 结尾,配置时使用前缀 TimeRange
 */
@Component
public class TimeRangeRoutePredicateFactory extends AbstractRoutePredicateFactory<TimeRangeRoutePredicateFactory.Config> {

    public TimeRangeRoutePredicateFactory() {
        super(Config.class);
    }

    /**
     * 配置类:接收 YAML 中的参数
     */
    public static class Config {
        private String startTime; // 格式 HH:mm:ss
        private String endTime;   // 格式 HH:mm:ss
        // Getter and Setter...
    }

    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        return exchange -> {
            LocalDateTime now = LocalDateTime.now();
            int currentTotalMinutes = now.getHour() * 60 + now.getMinute();
            
            // 简单解析配置的时间字符串
            String[] startParts = config.getStartTime().split(":");
            String[] endParts = config.getEndTime().split(":");
            
            int startTotalMinutes = Integer.parseInt(startParts[0]) * 60 + Integer.parseInt(startParts[1]);
            int endTotalMinutes = Integer.parseInt(endParts[0]) * 60 + Integer.parseInt(endParts[1]);

            // 判断当前时间是否在配置范围内
            return currentTotalMinutes >= startTotalMinutes && currentTotalMinutes <= endTotalMinutes;
        };
    }
}

YAML 配置:

predicates:
  - TimeRange=09:00,18:00 # 仅在9点到18点间生效

3.2 自定义全局过滤器:统一鉴权

全局过滤器适用于鉴权、日志记录等横切关注点,无需在路由中单独配置。

import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * 自定义全局过滤器:AuthGlobalFilter
 */
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 1. Pre 阶段:获取 Token
        String token = exchange.getRequest().getHeaders().getFirst("Authorization");

        // 2. 业务逻辑:简单鉴权
        if (token == null || !token.startsWith("Bearer ")) {
            // 鉴权失败,直接返回 401,中断后续过滤器链
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }

        // 3. 传递请求:将用户信息放入 exchange 属性,供下游服务使用
        exchange.getAttributes().put("userId", "user_123");
        
        // 4. 继续执行后续过滤器
        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
            // Post 阶段:响应返回后的逻辑
            System.out.println("全局过滤器:响应已返回");
        }));
    }

    @Override
    public int getOrder() {
        // 返回值越小,优先级越高。鉴权通常需要在最前面执行
        return -1; 
    }
}

4. 集群化部署与高可用

Spring Cloud Gateway 是无状态的,集群部署的核心在于负载均衡状态共享

4.1 架构拓扑

graph LR
    Client --> LB[Nginx/SLB]
    LB --> GW1[Gateway Instance 1]
    LB --> GW2[Gateway Instance 2]
    GW1 --> Redis[(Redis Cluster)]
    GW2 --> Redis
    GW1 --> Nacos[(Nacos Registry)]
    GW2 --> Nacos

4.2 关键配置要点

  1. 共享限流状态
    如果使用内置的 RequestRateLimiter,必须配置 Redis,确保所有实例共享令牌桶状态,否则限流会失效 。
spring:
  redis:
    host: 192.168.1.100
    port: 6379
  cloud:
    gateway:
      routes:
        - id: limited_route
          uri: lb://my-service
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10 # 每秒填充10个令牌
                redis-rate-limiter.burstCapacity: 20 # 桶容量20
                key-resolver: "#{@ipKeyResolver}" # 按IP限流
  1. 动态路由刷新
    在集群中,推荐结合 Nacos Config 实现动态路由。将路由配置存储在 Nacos,利用 @RefreshScope 或监听配置变更事件,调用 RouteDefinitionWriter 更新内存路由表,避免重启服务。
  2. 健康检查与负载均衡
    • 在 Nginx 中配置 upstream,指向所有 Gateway 实例。
    • 启用 Actuator 健康端点 /actuator/health,让负载均衡器能够自动剔除故障节点。

5. 总结

Spring Cloud Gateway 凭借其丰富的内置断言与过滤器,能够应对绝大多数路由场景;通过自定义扩展,可以灵活处理复杂业务逻辑;而基于无状态设计共享存储(Redis/Nacos),可以轻松实现高可用的集群部署。

最佳实践建议:

  • 优先使用内置组件:如 StripPrefix, AddRequestHeader 等,减少代码维护成本。
  • 避免阻塞:在自定义过滤器中严禁执行同步阻塞操作(如 JDBC 查询),应使用 Reactive 客户端。
  • 统一日志与链路追踪:集成 Micrometer Tracing,确保链路 ID 在网关和后端服务间透传,便于问题排查。
0

评论区