响应与策略
send().await 返回 Response 时,只有响应头到了。body 还在连接上,要靠 bytes、text、json、chunk 或 bytes_stream 一块块拉出来;拉的过程中经过 tower-http 的解压,经过 reqwest 自己包的读超时和总超时,读完了 HTTP/1.1 连接才回到池里。这是响应主线。
另一半是挂在请求上的策略:重定向、重试和 cookie 是 tower 栈里的层(栈的顺序见 执行与 Pending),超时不是层,而是分散在 Pending、响应体包装和连接器三处;最后一切失败都变成同一个 reqwest::Error,原因藏在 source() 链里。
代码分布(tag v0.13.5,.rs 行数含测试和文档注释):src/async_impl/response.rs 508 行,src/async_impl/body.rs 486 行(后半是两个超时包装),src/error.rs 543 行,src/redirect.rs 454 行,src/retry.rs 491 行,src/cookie.rs 292 行。解压在 tower-http 0.6.11 的 decompression 模块里,reqwest 只按 feature 打开算法。
- 响应体:五种读法,
text怎么从Content-Type和 BOM 选字符集;error_for_status只看状态码;gzipfeature 让 tower-http 的Decompression加Accept-Encoding并按字节精确匹配Content-Encoding解压;body 不读完时 HTTP/1.1 和 HTTP/2 的连接各自怎样。 - 超时:
timeout、read_timeout、connect_timeout分别在PendingRequest、响应体包装和连接器里实现;服务器卡在握手、响应头前、响应体中间三个阶段,各自是谁触发、错误长什么样。 - 重定向:
redirect::Policy(默认最多 10 次)怎么接到 tower-http 的FollowRedirect上,跨域时去掉哪些头。 - 重试:0.13 的
retry模块,默认只重试哪些错误,重试预算按什么范围计。 - 错误:
Error是一个指针,Kind七种;哪些is_*只看种类、哪些沿source()链找;链上的 hyper、io、rustls、serde_json 错误怎么取出来;URL 里的密钥和without_url。 - cookie:
cookie_store开关、Jar与CookieStoretrait,cookie 怎么跟着重定向走。
flowchart TB send["send().await"] --> head["Response:只有头"] head --> read["bytes text json chunk"] read --> tt["TotalTimeoutBody"] tt --> rt["ReadTimeoutBody"] rt --> dec["Decompression 体"] dec --> inc["hyper Incoming"] inc --> pool["读完:连接回池"] read --> err["reqwest::Error"]
图里从上往下是一次读调用穿过的包装,从外到内:总超时、读超时(只在设置了时才有)、解压、hyper 的 Incoming。每一层都可能出错,错误最后都被读方法包成 Kind::Decode,见 错误。
💬 关联讨论
发起讨论加载中...