fasthttp.RequestCtx 与 *http.Request 不兼容:前者复用对象、无 context.Context,后者新建实例且依赖上下文;PostBody() 等返回切片需复制,Client 需调大 MaxIdleConnDuration,router.Handler 非 http.Handler。

fasthttp.RequestCtx 不能当 *http.Request 用
这是最常踩的坑:把 fasthttp.RequestCtx 直接塞进原本为 net/http 写的中间件、日志器或鉴权逻辑里,结果 panic 或静默丢数据。根本原因不是“写法不对”,而是两套模型完全不兼容——fasthttp 复用上下文对象,net/http 每次新建;前者没 context.Context 字段,后者依赖它做超时和取消。
- 别试图调
ctx.Context()—— 它返回nil,硬塞context.WithTimeout会失效 - 要传关键信息,手动提取:
c.Method()、c.URI().String()、c.RemoteAddr(),再喂给原有逻辑 - 想模拟 context 行为?用
c.SetUserValue("timeout", time.Now().Add(5*time.Second))+ 自己检查,别绕弯 - 健康检查、指标上报、简单表单接收这类纯 API 路由,才是安全切入口;含复杂中间件链的主路由先别动
goroutine 里用 PostBody() 必须复制字节
fasthttp 为省 GC 开销,复用底层缓冲区,所以 ctx.PostBody() 返回的是内部切片指针。一旦你把它扔进 goroutine 异步处理,等真正读的时候,内存可能已被下一个请求覆盖,数据错乱或 panic。
- 错误写法:
go process(ctx.PostBody())——ctx下一秒就被复用了 - 正确写法:
body := append([]byte(nil), ctx.PostBody()...),立刻复制一份 - 同理:
ctx.FormValue("x")、ctx.QueryArgs().Peek("y")等所有 Peek/Value 类方法返回的 []byte 都得复制再用 - 如果频繁分配小 buffer,考虑用
sync.Pool管理[]byte,但注意别池化太大的 slice,反而增加 GC 压力
Client 默认连接池太激进,压测就 timeout
开箱即用的 fasthttp.Client 把 MaxIdleConnDuration 设得极短(默认约 1 秒),线上一并发,立刻出现 timeout: timed out waiting for idle connection 或 connection refused。这不是后端扛不住,是客户端自己把连接池耗尽又不敢复用。
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
- 必须显式配置:
client.MaxIdleConnDuration = 30 * time.Second - 如果调多个后端,建议按 host 分 client 实例,避免争抢连接池
- 别设成 5 分钟以上——空闲连接占着 fd 不放,系统级文件描述符容易耗尽
- 对比
net/http的Transport.IdleConnTimeout,两者语义一致,但fasthttp默认值危险得多
router.Handler 不等于 http.Handler,别混着注册
用 fasthttprouter 时,它的 router.Handler 是个 fasthttp.RequestHandler 类型函数,签名是 func(ctx *fasthttp.RequestCtx)。如果你拿它去注册到 http.Server 或塞进 chi 中间件链,编译不过或运行时报类型错误。
立即学习“go语言免费学习笔记(深入)”;
- 启动服务只能用:
fasthttp.ListenAndServe(":8080", router.Handler) - 没有
http.Handler兼容层,别指望chi.WrapHandler(router.Handler)这种魔法 - 需要日志/trace?自己在 handler 开头加:
log.Printf("%s %s from %s", c.Method(), c.URI(), c.RemoteAddr()) - 它支持自动修正路径斜杠和大小写,但只对注册的路由生效;405 和 OPTIONS 是内置的,不用额外写
fasthttp 不是 net/http 的平替,它是另一条路——快,但得按它的规则走。最容易被忽略的,其实是那句“复用 ctx 对象”带来的所有副作用:不能跨 goroutine 持有、不能缓存原始字节引用、不能依赖标准库生态。接受这个前提,才能真正用稳。


















