Rust in Everything
基于 axum 0.8.9

常见坑

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

  1. the trait bound fn(...) {handler}: Handler<_, _> is not satisfied:future 不是 Send、body 提取器不在最后、超过 16 个参数、返回值没实现 IntoResponse、参数不是提取器,五种原因同一句话;#[debug_handler] 在 debug 构建里逐条说出是哪一种。
  2. Path segments must not start with : 与 Invalid route、Overlapping method route:0.7 的 /:id 写法、matchit 判定的冲突、同一方法注册两次,都在构造 Router 时 panic;without_v07_checks 会把 /:id 当成字面量。
  3. Expected request with Content-Type: application/json 与 400 / 422:curl -d 和只传字符串的 fetch 都拿到 415;空 body 是 400,字段对不上是 422;Option<Json<T>> 会把没带头的 JSON 静默当成 None。
  4. Failed to buffer the request body: length limit exceeded:默认 2 MiB,读到上限才拒绝;回完 413 就关连接,大上传的客户端可能只看到 reset;DefaultBodyLimit 只套在已经存在的路由上。
  5. expected Router, found Router<AppState>:忘了 with_state、with_state 写在 route 前面、返回类型写错,报在 nest、get(handler)、oneshot 等不同位置。
  6. 中间件没生效:.layer 之后加的路由不受影响、route_layer 与 404 / 405、执行顺序、Handler::layer 每个请求重新套一次。
  7. /foo/ 返回 404:/foo 和 /foo/ 是两个路由。
  8. tower 中间件的 BoxError 套不上 Router:Router::layer 要求错误类型是 Infallible,会出错的 tower 中间件要先经过 HandleErrorLayer。
  9. Option<Query<T>> 编译不过:0.8 正式版前去掉了 Query 的 OptionalFromRequestParts 实现。
  10. (StatusCode, Json) 序列化失败仍返回你给的状态码:元组最后设状态码,盖掉了 Json 自己的 500;修复不在 0.8.9 里。
flowchart TB
  build["装配主线:编译期"] --> p1["1 Handler 不满足"]
  build --> p5["5 状态类型对不上"]
  build --> p8["8 BoxError"]
  build --> p9["9 Option Query"]
  boot["装配主线:启动时"] --> p2["2 路由 panic"]
  boot --> p6["6 中间件没生效"]
  req["请求主线"] --> p3["3 Json 415、400、422"]
  req --> p4["4 413"]
  req --> p7["7 尾斜杠 404"]
  req --> p10["10 状态码盖掉 500"]
  p9 --> p1
  p6 --> p4

1、5、8、9 是编译错误,2 在启动时 panic;其余几个程序照常运行,要等请求来了才看得出不对,6 的原因却出在装配时 .layer 的位置上。图里两条额外的线:第 9 个在编译器眼里就是第 1 个(报的也是 Handler<_, _> 不满足);第 6 个的规则也是第 4 个里「加了 DefaultBodyLimit::max 还是 413」的原因。读之前最好先读过 Handler trait、FromRequestParts 与 FromRequest 和 layer 与 route_layer。

💬 关联讨论

发起讨论
加载中...