路由
上一部分讲到 handler 返回 Response 为止。这一部分往外走一层:Router 是什么、一个请求怎么在它里面找到 handler,以及为了让各种 handler 和服务住进同一张表,axum 付出了什么。路由分两级:先按路径(matchit 树),再按方法(MethodRouter)。两级之下的端点都是同一个类型 Route。
- Router 的内部结构:
Router是Arc<RouterInner>,里面两个PathRouter(路由和 fallback)加一个兜底的catch_all_fallback;matchit 树只存RouteId,端点在旁边的表里;改动时Arc::try_unwrap成功就原地改,否则复制全部端点;请求依次交给三处,匹配上的写MatchedPath和路径参数。 - matchit 与路径语法:matchit 0.8.4 的
/{id}、/{*rest},0.7 的/:id写法在 0.8 会 panic 并提示without_v07_checks;哪些路由算冲突、在注册时就 panic。 - MethodRouter:每个 HTTP 方法一个槽,
HEAD请求在没有head槽时交给get槽;没有匹配的方法时回 405 并带Allow头;同一方法注册两次 panic。 - nest、merge 与 fallback:
nest把子路由加上前缀摊平进父路由树,nest_service把子服务整个挂上去;merge合并两棵树;fallback 在嵌套与合并时归谁。 - Route 与类型擦除:
Route是BoxCloneSyncService的包装,每个请求克隆一次、future 装箱一次,每多一层 layer 再多一份;欠状态的 handler 先存成BoxedIntoRoute;最外层的RouteFuture补Content-Length、清空 HEAD 的 body。
flowchart TB
req["Request"] --> router["Router:Arc RouterInner"]
router --> pathr["PathRouter:按路径"]
pathr --> ep{"Endpoint"}
ep -->|"route"| mr["MethodRouter:按方法"]
ep -->|"route_service、nest_service"| rt["Route"]
mr --> rt2["方法槽里的 Route"]
rt --> svc["handler 或服务"]
rt2 --> svc
第 1 章和第 5 章讲两头的数据结构,中间三章讲规则。中间件怎么套到这些 Route 上,在下一部分的 layer 与 route_layer。
💬 关联讨论
发起讨论加载中...