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 降序执行。理解这一点,才能正确安排多个过滤器的协作关系。
RouteLocator:把定义变成可执行路由
RouteLocator 是路由定位器,它的核心方法是根据请求找到匹配的 Route。它并不直接参与请求转发,而是负责“查表”:遍历当前所有可用的路由定义,逐个用断言去匹配请求,返回第一个匹配成功的路由。如果没有任何路由匹配,就返回空,最终由网关返回 404。
RouteLocator 的实现通常依赖 RouteDefinitionRepository 提供路由定义。在 Spring Cloud Gateway 中,默认的路由定位器会从配置中加载路由,也可以通过自定义 RouteLocator 实现动态路由。理解 RouteLocator 的意义在于:它把“路由定义”和“路由匹配”解耦,定义可以来自不同来源,而匹配逻辑保持一致。
RouteDefinitionRepository:路由定义的存储与加载
RouteDefinitionRepository 是路由定义的仓库接口,负责路由定义的读取、保存和删除。默认实现会从配置文件(如 application.yml)中加载路由定义。当我们需要动态增删路由时,可以实现这个接口,把路由定义存到数据库、Redis 或配置中心,再配合事件刷新机制让网关感知变化。
它的典型方法包括:获取所有路由定义、根据 id 获取、保存路由定义、删除路由定义。通过实现这些方法,路由就不再是启动时固定的,而是可以在运行时动态调整。这对于多租户、灰度发布、A/B 测试等场景非常有用。
一个完整的路由定义示例
下面是一个基于 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。响应返回时,过滤器按相反顺序执行后置逻辑。
掌握 Route、Predicate、Filter 三要素,以及 RouteDefinition、RouteLocator、RouteDefinitionRepository 的职责分工,就能读懂网关的请求处理链路,也能在需要时自定义路由、断言和过滤器,让网关按预期工作。