改 body
作用点主线的第三个时刻:响应头已经出来(或者请求已经交给内层),body 还在一帧一帧地流。这一部分的模块都在 poll_frame 里干活,换掉的是 body 的类型:
- 共享内核:content_encoding 与 compression_utils:
Encoding枚举、SupportedEncodingstrait、WrapBody。Body → Stream → AsyncRead → 编解码器 → Body一条管道,压缩、解压两个方向共用;内层 body 的错误怎么穿过io::Error原样回来;编解码器读完之后还要再看一眼内层。 - 压缩的内部:谓词是类型参数;
CompressionBody的变体按 feature 出现,靠pin_project_cfg!展开成 16 份枚举;没压的 body 才转发size_hint;CompressionLevel对 br、zstd 的两处特殊处理。 - 响应解压:
call时只补Accept-Encoding,响应回来按Content-Encoding逐字节匹配;zstd 开多成员、gzip 不开,同样两段 gzip 分一帧和分两帧结果不同;0.7.1 修好的结尾逻辑。 - 请求解压:服务端方向,同一套零件;不认识的编码回 415;响应一律装箱;没有解压后大小上限,和
RequestBodyLimitLayer谁在外层决定限的是哪一边的字节。 - 超时一族:
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 卷 响应体 讲过,这里只链过去。
💬 关联讨论
发起讨论加载中...