Rust in Everything
基于 tower-http 0.7.1

改请求

这一部分的模块都很小,核心逻辑往往只有几行:在 call 时改一下请求(加头、改 URI、放扩展、换 body 类型),或者在响应 future 完成时改一下状态码和头。它们不碰 body 里的数据,所以没有自己的 body 类型。难的不是单个模块,而是它们和别的层的先后:同一个层放在另一个层里面还是外面,结果可能完全不同。

  1. set_header 一族:MakeHeaderValue 接固定值或闭包;三种模式共用一个 apply;请求侧闭包的状态跟着服务实例累积,响应侧每个请求从克隆起步;0.6.11 的多头版本装箱,Clone 分两个版本才修全。
  2. 搬运请求标识与头:客户端带来的 x-request-id 原样采用;PropagateRequestId 在 call 时读请求头,必须放在 SetRequestId 里面,反了的话生成的 id 回不到响应里;SetSensitiveHeaders 只打标记,请求侧要放在 Trace 外面。
  3. 小型改写层:NormalizePath 只改 URI 不重定向,顺手把开头的多个斜杠并成一个;append_trailing_slash 会让 0.7.0 的 ServeDir 对文件回 404;SetStatus 不看内层给了什么。
  4. 校验与鉴权:AcceptHeader 不看 q 值,has_header_value 只看第一个值;弃用的 bearer 按字节比较;AddAuthorization 默认不标敏感;AsyncRequireAuthorization 在整个鉴权期间占着内层的就绪名额。
flowchart TB
  req[请求] --> c1["call 时:改请求"]
  c1 --> sh["SetRequestHeader、SetRequestId、AddExtension"]
  c1 --> rw["NormalizePath、MapRequestBody"]
  c1 --> mark["SetSensitiveRequestHeaders、AddAuthorization"]
  c1 --> gate{"ValidateRequestHeader"}
  gate -->|拒绝| short[短路:401 / 403 / 406]
  gate -->|放行| inner[内层]
  inner --> c2["响应 future 完成时:改响应头和状态码"]
  c2 --> rs["SetResponseHeader、PropagateRequestId、PropagateHeader、SetStatus、MapResponseBody"]

贯穿四章的一条规律:请求侧的层在 call 里直接用 &mut self 上的配置,响应侧的层要把配置克隆进 future,因为 future 比 &mut self 的借用活得久。SetResponseHeader、MapResponseBody 比它们的请求侧版本多一个 Clone 约束,带状态的闭包放在两侧行为不同,都是这个原因。

💬 关联讨论

发起讨论
加载中...