Rust in Everything
基于 tower-http 0.7.1

改 body

作用点主线的第三个时刻:响应头已经出来(或者请求已经交给内层),body 还在一帧一帧地流。这一部分的模块都在 poll_frame 里干活,换掉的是 body 的类型:

  1. 共享内核:content_encoding 与 compression_utils:Encoding 枚举、SupportedEncodings trait、WrapBody。Body → Stream → AsyncRead → 编解码器 → Body 一条管道,压缩、解压两个方向共用;内层 body 的错误怎么穿过 io::Error 原样回来;编解码器读完之后还要再看一眼内层。
  2. 压缩的内部:谓词是类型参数;CompressionBody 的变体按 feature 出现,靠 pin_project_cfg! 展开成 16 份枚举;没压的 body 才转发 size_hint;CompressionLevel 对 br、zstd 的两处特殊处理。
  3. 响应解压:call 时只补 Accept-Encoding,响应回来按 Content-Encoding 逐字节匹配;zstd 开多成员、gzip 不开,同样两段 gzip 分一帧和分两帧结果不同;0.7.1 修好的结尾逻辑。
  4. 请求解压:服务端方向,同一套零件;不认识的编码回 415;响应一律装箱;没有解压后大小上限,和 RequestBodyLimitLayer 谁在外层决定限的是哪一边的字节。
  5. 超时一族:Timeout 与四个 body 计时器;TimeoutBody 每帧重开、从第一次 poll 才开始计时,DeadlineBody 套上就开始;TimeoutBody 不转发 size_hint,响应会变成 chunked。
flowchart TB
  core["共享内核:Encoding、SupportedEncodings、WrapBody"]
  core --> comp["压缩(S):响应 body 编码"]
  core --> dec["响应解压(C):响应 body 解码"]
  core --> rdec["请求解压(S):请求 body 解码"]
  core -.->|"只用协商"| sd["ServeDir 预压缩(08 服务)"]
  tmo["超时一族(S/C):body 套计时器"]

四个方向(请求/响应 × 压缩/解压)只实现了三个,没有「请求压缩」;超时一族和编码无关,放在这里是因为它也只在 body 流动时起作用。行为层面的内容(协商规则、DefaultPredicate、改哪些头、GZIP 不解压、TimeoutLayer 的同时到期)已经在 axum 卷 压缩、其余常用中间件 和 reqwest 卷 响应体 讲过,这里只链过去。

💬 关联讨论

发起讨论
加载中...