Rust in Everything
基于 tower-http 0.7.1

tower-http 源码解析

这一卷对着 tower-http 0.7.1 读源码:

crate版本tagcommit日期
tower-http0.7.1tower-http-0.7.1c9414512026-08-31

tower-http 是 tower 的 HTTP 版中间件库:CORS、压缩、解压、超时、Trace、重定向、静态文件,几十个模块,src/ 一共 3.16 万行(含模块内测试)。它只认 http::Request / http::Response 和 http_body::Body,不依赖 hyper,也不依赖 axum,所以同一个 layer 能套在 axum 的 Router 上、纯 hyper 服务上,也能套在 hyper-util 的客户端外面。

axum 卷的 tower-http 部分讲了 Web 应用最常用的几样「怎么用、在 axum 里会怎样」,reqwest 卷讲了客户端用到的重定向和解压。这一卷讲它们没讲的:模块内部怎么组织、模块之间怎么复用、客户端方向和服务端方向的对照,以及那几个在别处几乎没出现过的模块(classify、on_early_drop、metrics)。

tower 卷的主线是 poll_ready 的背压,在这里几乎不存在:tower-http 的中间件把 poll_ready 原样转发给内层,不占资源。全卷换成两条主线:

  • 作用点主线(三个时刻):一个中间件只能在三处改写请求或响应:call 时(改请求,或者不调内层直接短路)、响应 future 完成时(改状态码和头,决定换不换 body)、body 流动时(poll_frame 逐帧改写或观察)。每章开头标出本模块占了哪几处。
  • 结局主线(一个请求怎么算结束):成功还是失败、正常结束还是被放弃,被拆成三件独立的事:classify 判断「什么算失败」,trace 的 body 包装判断「什么算结束」,Drop 守卫判断「什么算放弃」。
flowchart TB
  intro[00 导读] --> overview[01 全景]
  overview --> skeleton[02 共同骨架]
  skeleton --> req[03 改请求]
  skeleton --> guard[04 拦请求]
  skeleton --> body[05 改 body]
  skeleton --> outcome[06 结局]
  body --> client[07 客户端]
  outcome --> client
  body --> services[08 服务]
  client --> design[09 设计取舍]
  services --> design
  req --> design
  guard --> design
  design --> pit[10 常见坑]
  pit --> site[11 在本站中]
  site --> hands[12 动手]

从「导读」开始。只想会用 tower-http 的读者,先读 01、02 和 06;想读懂实现的,按顺序读。

目录

部分内容
00 导读怎么读这一卷;源码地图:35 个 feature、模块之间的依赖
01 全景tower-http 解决什么问题;一个请求穿过三个时刻
02 共同骨架每个模块都有的四件套与三个宏;ServiceBuilderExt 与 ServiceExt;body 模块
03 改请求set_header 一族、请求标识与头、小型改写层、校验与鉴权
04 拦请求CORS 的内部、CSRF、body 大小限制
05 改 body编码内核、压缩、响应解压、请求解压、超时一族
06 结局classify、Trace 的内部、CatchPanic、InFlightRequests、OnEarlyDrop
07 客户端FollowRedirect 的策略;拼一个客户端栈
08 服务ServeDir 的 Backend trait;Redirect 服务
09 设计取舍八个设计决定:换来什么、付出什么、由谁来补
10 常见坑CORS 配置 panic、多余字节、限额被解压绕过、307 原样返回、日志里的 token 等十一个
11 在本站中本站用到的两样与手写的四样;升到 0.7.1 会怎样
12 动手从零写一个跨三个时刻的中间件

💬 关联讨论

发起讨论
加载中...