Tower Service 适配层
This content is not available in your language yet.
Tower Service 是 Axum 的通用接缝。路由器、单条路由、异步处理函数和中间件最终都要表现成“接收 Request、返回 Future”的对象。
先给答案:Tower Service 是 Axum 的通用接缝
Section titled “先给答案:Tower Service 是 Axum 的通用接缝”Tower Service 是 Axum 的通用接缝。路由器、单条路由、异步处理函数和中间件最终都要表现成“接收 Request、返回 Future”的对象。 正文沿“适配链 -> 四层对象 -> pollready 为什么看起来总是 Ready”展开:先确认入口和状态归属,再跟踪控制流或数据流的推进,最后落到对外可观察的结果。
主要失效边界集中在“在注册路由前调用 layer、内层 Service 返回任意错误、自定义 Service 不可 Clone”这些场景。它们破坏的是容量、顺序、并发或生命周期前提;排查时应先确认状态是否仍由正确对象持有,再核对推进条件和清理路径。
handler fn -> Handler<T, S> -> HandlerService<H, T, S> -> Route<BoxCloneSyncService> -> MethodRouter -> Router -> make service per connectionHandlerService保存 handler 与 state,定义在axum/src/handler/service.rs:22-27;其Service<Request<B>>实现在handler/service.rs:146-168。Route<E>把具体 service 擦除成BoxCloneSyncService<Request, Response, E>,见routing/route.rs:31-35。MethodRouter<S, E>保存各 HTTP method endpoint 与 fallback,见routing/method_routing.rs:549-558;请求分派在method_routing.rs:1200-1251。Router<S>组合 path router、fallback router 和默认 fallback,见routing/mod.rs:86-94;最终调用在routing/mod.rs:452-460。
Router 在状态补齐后实现 Service<Request<B>>(routing/mod.rs:575-597),Route 的 call 会替换内部 service 再调用,避免违反 Tower 对并发调用准备状态的约束(routing/route.rs:88-106)。
poll_ready 为什么看起来总是 Ready
Section titled “poll_ready 为什么看起来总是 Ready”Axum 的大多数路由 Service 在 poll_ready 返回 Ready,而真正可能失败或等待的逻辑放进返回 Future。原因是路由层需要可克隆、可并发地驱动内层服务;具体背压常由更外层 Tower middleware 或 Hyper 连接管理表达。
为什么不用一个巨型枚举保存所有 Handler 类型
Section titled “为什么不用一个巨型枚举保存所有 Handler 类型”替代方案:为不同参数数量、返回类型和 middleware 组合生成一个封闭枚举。
为什么不行:组合空间开放且无限;任何用户自定义 Service 都会迫使框架修改枚举。
证据:HandlerService 保留静态泛型,进入路由表后由 Route 在 routing/route.rs:31 做 trait-object 擦除,开放扩展与可控二进制体积同时成立。
Layer 插入位置
Section titled “Layer 插入位置”| API | 包裹范围 | 坐标 |
|---|---|---|
Router::layer |
已注册的全部路由与 fallback | routing/mod.rs:302-332 |
Router::route_layer |
已注册的路由,不包 fallback | routing/mod.rs:332-370 |
MethodRouter::layer |
当前方法路由中的 endpoints | routing/method_routing.rs:992-1038 |
Handler::layer |
单个 handler | handler/mod.rs:190-218 |
| 场景 | 现象 | 原因 | 规避 |
|---|---|---|---|
在注册路由前调用 layer |
后加路由没有 middleware | layer 只变换当前服务树 | 最后统一 layer,或用 builder 固化顺序 |
| 内层 Service 返回任意错误 | 服务器无法形成响应 | Hyper 连接要求请求错误被处理 | 使用 HandleErrorLayer 转响应 |
| 自定义 Service 不可 Clone | 无法装入路由 | 路由分支和连接需要克隆 | 外包 Arc 或提供 Clone handle |
把 poll_ready 当业务限流 |
Axum 路由通常始终 Ready | 背压不在这一层表达 | 使用 Tower concurrency/load-shed layer |
“静态泛型留在叶子、动态擦除放在聚合边界”适用于插件系统、命令总线和编译器 pass 管线:叶子保留优化空间,容器只统一最小协议。
面试锚点
- Handler 如何变成 Tower Service?
Route为什么要做类型擦除?layer与route_layer有什么差异?