Rust in Everything
基于 hyper 1.12.0

常见坑

每一章对着一个报错或者一个现象:先用一个最小的程序把它复现出来,再到源码里找它是在哪一行产生的,最后给出修法,修法也跑一遍。机制本身在前面的章节讲过的,这里只链过去,不再重复。

  1. connection closed before message completed:IncompleteMessage。最常见的是客户端从池里拿到一条服务端刚关掉的空闲连接;对端在响应头中途关闭、请求被送进一个直接断开的代理,报的也是它。body 读到一半断开报的是另一个错误。
  2. dispatch task is gone:连接任务所在的运行时没了。典型场景是多个 #[tokio::test] 共用一个 static 的 Client:串行全过,并行约一半的运行失败。只换执行器不够,socket 也要在长寿的运行时上建。
  3. You must supply a timer. 与 timeout header_read_timeout set, but no timer set:开了 HTTP/2 keep-alive 或显式设了读头超时,却没给 timer。auto::Builder 的两半各有各的 timer;panic 只杀掉一条连接,服务看起来还活着。
  4. header_read_timeout 不生效,半个前言挂住连接:axum::serve 和 auto::Builder::new 都不设 timer,读头超时和 keep-alive 空闲上限都不存在;设了 timer,ReadVersion 这一步仍然没有超时。
  5. invalid HTTP version parsed 与 found HTTP2 preface:HTTP/2 客户端打到只会 HTTP/1 的服务端,或 HTTP/1 客户端打到 HTTP/2 服务端、TLS 端口。TLS 握手打到明文端口报的却是方法名错误。
  6. message head is too large:请求头超过 max_buf_size 或 max_header_size,服务端回 431。
  7. 连接没有被复用:响应 body 没读完、空闲超时、max_idle_per_host,连接回不到池里。
  8. 优雅停机一直不结束:长连接不会自己结束,shutdown() 要配超时。
  9. 一个慢请求卡住同一连接上后面的请求:HTTP/1 一条连接上的请求串行处理;HTTP/2 每个流一个任务。
  10. SOCKS error: failed to create underlying connection:直接用 SocksV5 时,默认 HttpConnector 的 enforce_http 拒绝 socks5://,或代理 URI 没写端口被按 80 连;原因只在 {:?} 里。
  11. tunnel error: unsuccessful:代理对 CONNECT 回了 200、407 以外的状态码,状态码不进错误;用 hyper 自己的客户端发 CONNECT 才拿得到。
flowchart TB
  cli["客户端主线"] --> p1["1 连接提前关闭"]
  cli --> p2["2 dispatch task 没了"]
  cli --> p7["7 连接不复用"]
  cfg["建连接时的配置"] --> p3["3 缺 timer"]
  srv["服务端主线"] --> p4["4 慢连接挂住"]
  srv --> p5["5 版本号解析失败"]
  srv --> p6["6 请求头太大"]
  srv --> p8["8 停机不结束"]
  srv --> p9["9 慢请求堵住连接"]
  prx["经代理建连接"] --> p10["10 SOCKS 连不上代理"]
  prx --> p11["11 CONNECT 被拒"]
  p3 --> p4
  p1 --> p5

图里两条额外的线:3 和 4 是同一个开关(timer)的两面,给了不该给的选项会 panic,没给 timer 又会让默认超时悄悄失效;1 和 5 常常一起出现在「协议或端口弄错了」的场合,对端回什么字节决定你看到哪一个。读之前最好先读过 Dispatcher、conn::http1 客户端 和 Executor 与 Timer。

💬 关联讨论

发起讨论
加载中...