3、路由原理:路由表、路由规则、路由匹配算法详解
好,咱们今天聊聊路由原理。说实话,很多同学用网关用了好几年,问起路由到底怎么工作的,往往就卡住了。我当年刚接触微服务时也踩过这个坑——配置了一堆路由规则,结果请求就是过不去。后来一查,原来是路由表匹配顺序搞反了。
这一节,我把路由的核心三要素掰开揉碎讲清楚:路由表、路由规则、路由匹配算法。你理解透了,以后配置网关就跟玩似的。
3.1 路由表:网关的“交通地图”
路由表是什么?说白了,它就是一张映射表。这张表告诉网关:“当请求长这样时,你应该转发到那个服务去”。
我习惯把路由表想象成一张地铁线路图。每个入口站(请求路径)都对应一个出口站(目标服务)。没有这张图,网关就是个瞎子。
一个典型的路由表条目,通常包含这几个字段:
| 字段 | 含义 | 示例 |
|---|---|---|
| ID | 路由唯一标识 | route_user_service |
| Predicates | 匹配条件(路径、Header、参数等) | Path=/user/** |
| Filters | 过滤器链(请求进来后先处理什么) | AddRequestHeader, StripPrefix |
| URI | 目标服务地址 | lb://user-service |
| Order | 优先级(数字越小越优先) | 0 |
嗯,这里要注意:Order字段非常关键。我在项目中遇到过,两个路由规则都匹配同一个请求,结果因为Order没配好,请求跑到了错误的服务上。那次排查花了我整整一个下午。
3.2 路由规则:匹配的“游戏规则”
路由规则,就是网关用来判断“这个请求该走哪条路”的条件集合。Spring Cloud Gateway里,这些规则叫Predicates(断言)。
常见的路由规则有哪些?我给你列几个最常用的:
- Path 规则:按请求路径匹配。比如
/api/user/**匹配所有以 /api/user/ 开头的请求。 - Header 规则:按请求头匹配。比如要求请求头里必须带
X-Version=v2。 - Query 规则:按查询参数匹配。比如
?env=test才走这条路由。 - Method 规则:按HTTP方法匹配。比如只允许GET请求。
- Cookie 规则:按Cookie值匹配。灰度发布时常用。
你想想看,这些规则可以组合使用。比如:Path=/order/** AND Method=POST,意思就是“只有POST请求到/order路径的,才走这条路由”。
核心要点:路由规则是“与”关系——所有条件必须同时满足,才算匹配成功。
3.3 路由匹配算法:到底怎么找到那条路?
好,现在路由表有了,规则也定了。那网关收到一个请求后,到底是怎么找到对应路由的?
我把它拆成三步:
- 遍历路由表:网关从Order最小的路由开始,逐个检查。
- 执行断言:对每个路由,依次执行它的所有Predicates。只要有一个不通过,直接跳过。
- 命中第一条:一旦找到完全匹配的路由,立即停止搜索,执行转发。
为什么会这样设计?因为性能优先。网关每秒可能要处理成千上万个请求,如果每个请求都要遍历所有路由,那延迟就上去了。
我曾经在项目里犯过一个低级错误:把最通用的路由(比如 Path=/**)放在了Order最小的位置。结果所有请求都匹配到了它,后面的精细化路由永远没机会执行。嗯,这个坑我替你们踩过了。
避坑指南:路由Order的配置原则——精确的放前面,模糊的放后面。比如 /user/detail 应该排在 /user/** 前面。
3.4 实战:一个完整的路由配置示例
光说不练假把式。咱们看一个Spring Cloud Gateway的真实配置:
spring:
cloud:
gateway:
routes:
- id: user_service_route
uri: lb://user-service
predicates:
- Path=/api/user/**
- Header=X-Region, cn-*
filters:
- StripPrefix=1
- AddRequestHeader=X-Gateway, true
order: 1
- id: order_service_route
uri: lb://order-service
predicates:
- Path=/api/order/**
- Method=GET,POST
filters:
- StripPrefix=1
order: 2
- id: fallback_route
uri: lb://default-service
predicates:
- Path=/**
order: 999
这个配置什么意思?我解释一下:
- 请求
/api/user/list且 Header 里 Region 以 cn 开头 → 走 user-service - 请求
/api/order/123且是 GET 或 POST → 走 order-service - 其他所有请求 → 走 default-service(兜底路由)
我个人习惯,永远留一条兜底路由。这样即使前面的规则都没匹配上,请求也不会直接报404,而是有个优雅的降级处理。
3.5 路由匹配的常见陷阱
最后,我总结几个实际开发中容易踩的坑:
- 路径前缀问题:用了
StripPrefix记得检查路径是否被正确裁剪。我见过有人配了StripPrefix=2,结果路径只剩下一半。 - 负载均衡标识:URI 里用
lb://开头,网关才会走负载均衡。直接写http://localhost:8080就是硬编码。 - 路由顺序冲突:两个路由的 Order 相同,匹配顺序取决于加载顺序,这个不可控。所以 Order 一定要显式指定。
我的小技巧:调试路由时,可以开启网关的日志级别为 DEBUG,看 RoutePredicateHandlerMapping 的日志。它会打印出每个路由的匹配结果,排查问题特别方便。
好了,路由原理这块就讲到这里。下一节咱们聊聊动态路由——怎么在不重启网关的情况下,热更新路由规则。那个更有意思。