4. 路由核心三要素

在 Spring Cloud Gateway 中,一个请求从进入网关到被转发到后端服务,中间要经过一条完整的处理链。这条链的骨架由三个核心概念支撑:Route(路由)、Predicate(断言)和Filter(过滤器)。理解这三者的分工与协作,是掌握网关行为的关键。本节围绕它们展开,并进一步说明承载它们的 RouteDefinition、负责查找路由的 RouteLocator,以及存储路由定义的 RouteDefinitionRepository。

Route:一次转发的完整描述

Route 是网关中最基本的转发单元。它回答的是“什么样的请求,应该被转发到哪里,转发前后要做哪些加工”。一个 Route 由三部分组成:唯一标识 id、目标地址 uri,以及一组断言和一组过滤器。id 用于区分不同路由,uri 指明请求最终要到达的后端服务地址,断言决定这个路由是否匹配当前请求,过滤器则在匹配成功后对请求或响应做处理。

在代码层面,Route 通常不是直接手写的,而是通过 RouteDefinition 描述,再由框架构建成可执行的 Route。RouteDefinition 是路由的“定义结构”,它把路由的各个组成部分以数据的形式表达出来,便于从配置文件、数据库或 Java 代码中加载。其典型组成如下:

RouteDefinition
 ├─ id           路由唯一标识
 ├─ uri          目标地址,如 lb://order-service
 ├─ predicates   断言列表(PredicateDefinition)
 ├─ filters      过滤器列表(FilterDefinition)
 └─ metadata     元数据(可选,用于扩展)

其中 predicates 和 filters 都是列表,每个元素包含 name(断言或过滤器的名称)和 args(参数键值对)。例如一个断言可以写成 name=Path、args={pattern=/api/order/**},表示按路径匹配。这种“名称 + 参数”的结构让路由定义可以完全外部化,配置文件和数据库都能用同一种形式表达。

Predicate:判断请求是否匹配

Predicate 是 Java 8 的函数式接口,输入是请求上下文,输出是布尔值。在网关中,它的职责是判断当前请求是否满足某个条件。只有当一条路由的所有断言都返回 true 时,这条路由才会被选中。常见的断言包括:

  • Path:按请求路径匹配,如 /api/order/**;
  • Method:按 HTTP 方法匹配,如 GET、POST;
  • Header:按请求头匹配,如 X-Token 存在或等于某值;
  • Query:按查询参数匹配,如 ?debug=true;
  • Host:按主机名匹配;
  • After / Before / Between:按时间窗口匹配。

多个断言之间是“与”的关系。例如同时配置 Path 和 Method,请求必须既满足路径又满足方法才算匹配。断言的匹配过程发生在路由定位阶段,它决定了请求会落到哪一条路由上。如果没有任何路由匹配,网关会返回 404。

Filter:处理请求和响应

Filter 是网关的处理单元,分为前置处理和后置处理两个阶段。请求进入网关后,先按顺序执行各过滤器的前置逻辑,再转发到后端服务;收到后端响应后,再按相反顺序执行后置逻辑。这种“洋葱模型”让过滤器可以在请求发出前修改请求,也可以在响应返回前修改响应。

过滤器按作用范围分为两类:GatewayFilter 作用于单条路由,GlobalFilter 作用于所有路由。常见的内置过滤器包括:

  • AddRequestHeader:为请求添加请求头;
  • AddResponseHeader:为响应添加响应头;
  • StripPrefix:去掉路径前缀后再转发;
  • RewritePath:重写请求路径;
  • RequestRateLimiter:限流;
  • CircuitBreaker:熔断降级。

过滤器链的执行顺序由 order 值决定,order 越小越先执行。前置阶段按 order 升序执行,后置阶段按 order 降序执行。理解这一点,才能正确安排多个过滤器的协作关系。

Route 三要素协作与请求处理链 客户端 HTTP 请求 RouteLocator 路由定位器 查找匹配的 Route 遍历所有路由定义 Predicate 断言 Path / Method / Header Query / Host / Time 全部为 true 才匹配 匹配失败 → 404 Filter 过滤链 GatewayFilter(单路由) GlobalFilter(全局) 前置:改请求 后置:改响应 order 越小越先执行 后端服务 lb://order-service 转发请求 返回响应 RouteDefinition 组成结构 id uri predicates[] filters[] RouteDefinitionRepository 负责存储与加载这些定义 读取定义

RouteLocator:把定义变成可执行路由

RouteLocator 是路由定位器,它的核心方法是根据请求找到匹配的 Route。它并不直接参与请求转发,而是负责“查表”:遍历当前所有可用的路由定义,逐个用断言去匹配请求,返回第一个匹配成功的路由。如果没有任何路由匹配,就返回空,最终由网关返回 404。

RouteLocator 的实现通常依赖 RouteDefinitionRepository 提供路由定义。在 Spring Cloud Gateway 中,默认的路由定位器会从配置中加载路由,也可以通过自定义 RouteLocator 实现动态路由。理解 RouteLocator 的意义在于:它把“路由定义”和“路由匹配”解耦,定义可以来自不同来源,而匹配逻辑保持一致。

RouteDefinitionRepository:路由定义的存储与加载

RouteDefinitionRepository 是路由定义的仓库接口,负责路由定义的读取、保存和删除。默认实现会从配置文件(如 application.yml)中加载路由定义。当我们需要动态增删路由时,可以实现这个接口,把路由定义存到数据库、Redis 或配置中心,再配合事件刷新机制让网关感知变化。

它的典型方法包括:获取所有路由定义、根据 id 获取、保存路由定义、删除路由定义。通过实现这些方法,路由就不再是启动时固定的,而是可以在运行时动态调整。这对于多租户、灰度发布、A/B 测试等场景非常有用。

三要素协作关系小结:RouteDefinition 描述“路由长什么样”,RouteLocator 负责“找到匹配的路由”,Predicate 决定“是否匹配”,Filter 决定“匹配后怎么处理”。四者配合,构成网关请求处理的主干。

一个完整的路由定义示例

下面是一个基于 YAML 的路由定义示例,它把 /api/order/** 的请求转发到 order-service,并添加请求头和去掉前缀:

spring:
  cloud:
    gateway:
      routes:
        - id: order-route
          uri: lb://order-service
          predicates:
            - Path=/api/order/**
            - Method=GET,POST
          filters:
            - StripPrefix=1
            - AddRequestHeader=X-Gateway, spring-cloud-gateway

这条路由的匹配过程是:请求先经过 RouteLocator,找到 id 为 order-route 的路由;然后用 Path 和 Method 两个断言判断,只有路径以 /api/order/ 开头且方法为 GET 或 POST 时才匹配;匹配成功后进入过滤器链,先执行 StripPrefix=1 去掉 /api 前缀,再添加请求头 X-Gateway,最后转发到 order-service。响应返回时,过滤器按相反顺序执行后置逻辑。

注意:断言的匹配是“全部满足”才通过,过滤器则按 order 顺序执行。配置多个断言时,任何一个不满足都会导致该路由不匹配;配置多个过滤器时,order 值决定了它们的执行先后,前置升序、后置降序。

掌握 Route、Predicate、Filter 三要素,以及 RouteDefinition、RouteLocator、RouteDefinitionRepository 的职责分工,就能读懂网关的请求处理链路,也能在需要时自定义路由、断言和过滤器,让网关按预期工作。