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 路由匹配算法:到底怎么找到那条路?

好,现在路由表有了,规则也定了。那网关收到一个请求后,到底是怎么找到对应路由的?

我把它拆成三步:

  1. 遍历路由表:网关从Order最小的路由开始,逐个检查。
  2. 执行断言:对每个路由,依次执行它的所有Predicates。只要有一个不通过,直接跳过。
  3. 命中第一条:一旦找到完全匹配的路由,立即停止搜索,执行转发。

为什么会这样设计?因为性能优先。网关每秒可能要处理成千上万个请求,如果每个请求都要遍历所有路由,那延迟就上去了。

我曾经在项目里犯过一个低级错误:把最通用的路由(比如 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 的日志。它会打印出每个路由的匹配结果,排查问题特别方便。

好了,路由原理这块就讲到这里。下一节咱们聊聊动态路由——怎么在不重启网关的情况下,热更新路由规则。那个更有意思。