Rust in Everything
基于 reqwest 0.13.5

发请求

client.get(url).json(&x).send().await 这一行,在连接建立之前经过三段代码:RequestBuilder 把方法、URL、头和 body 攒成一个 Request,途中的任何错误都先存着;Client::execute_request 补上默认头,把请求同步地送进 ClientBuilder::build 组装好的 tower 栈,返回一个 Pending;body 的形态决定 hyper 最后在线上写 Content-Length 还是 chunked。这一部分是请求主线的前半段,后半段(连接从哪来)在 连接,响应在 响应与策略。

代码分布(tag v0.13.5,.rs 行数含测试):src/async_impl/request.rs 1151 行,src/async_impl/client.rs 3196 行(这一部分只读 execute_request、Pending 和 build 的结尾),src/async_impl/body.rs 486 行,src/async_impl/multipart.rs 754 行。实验程序在 exp-reqwest/req-lab,用一个直接读 TCP 字节的 HTTP/1.1 服务器看线上的请求原文。

  1. 请求构建:RequestBuilder 存的是 crate::Result<Request>,非法头、序列化失败都记成 builder error,到 send 才报;header 追加、headers 替换、json 不覆盖已有 Content-Type;URL 里的用户名密码变成 basic 认证头;0.13 起 query() / form() 要开 feature;流式 body 不能 try_clone。
  2. 执行与 Pending:execute_request 只查 scheme、补默认头(默认没有 User-Agent)、转 Uri;Accept-Encoding 和 cookie 由层加;栈从外到里是 Decompression、FollowRedirect、CookieService、Retry、HyperService;连接在第一次 poll 时才建,总超时却从 send() 起算。
  3. 请求体与 multipart:Body 是完整的 Bytes 或装箱的流,hyper 按 size_hint 选分帧;HTTP/1.1 下 GET 的流式 body 被静默丢弃;multipart::Form 的 67 字符边界和预先算出的 Content-Length,长度报错的两种后果。
flowchart TB
  rb["RequestBuilder"] --> send["send"]
  send --> exec["execute_request"]
  exec --> stack["tower 栈"]
  exec --> pend["Pending"]
  pend --> stack
  stack --> hyper["legacy Client"]
  hyper --> enc["hyper 编码 body"]
  body["Body"] --> rb
  form["multipart Form"] --> body

💬 关联讨论

发起讨论
加载中...