http.MaxBytesReader 对 Fiber 无效,因 Fiber 基于 fasthttp;应使用 fiber.BodyLimit 全局设限或 bodyLimitMiddleware 细粒度控制,上传文件需单独用 c.LimitRequestBody。

为什么不能直接用 http.MaxBytesReader 包裹 c.Request().Body
Fiber 底层用的是 fasthttp,不是标准库 net/http,所以 http.MaxBytesReader 对 c.Request().Body 完全无效——它只认 http.Request.Body 类型。强行套用会导致编译失败或运行时 panic(比如类型断言失败),而且根本起不到限制作用。
fiber.BodyLimit 是最简方案,但要注意生效范围
全局设置 BodyLimit 是最快的方式,但它只对未显式调用 c.Body() 或 c.BodyParser() 的请求生效;一旦你在 handler 里手动读取了 body(比如 c.Body()),Fiber 就不会再走内置限流逻辑。
- 在
fiber.New()时配置:fiber.New(fiber.Config{BodyLimit: 10 * 1024 * 1024})—— 限制所有路由为 10MB - 这个值是字节上限,超出后 Fiber 会直接返回
413 Payload Too Large,不进 handler - 注意:它不拦截 multipart 表单上传(
c.FormFile);上传文件大小需额外用c.LimitRequestBody或中间件控制
需要细粒度控制?写一个专用中间件
当你要对某几个路由单独设限(比如 /api/v1/upload 放宽到 50MB,其余保持 5MB),就得自己写中间件。核心是提前读取并校验原始 body 字节长度,再决定是否放行。
示例中间件:
func bodyLimitMiddleware(maxBytes int) fiber.Handler {
return func(c *fiber.Ctx) error {
// 只对 POST/PUT/PATCH 等可能带 body 的方法检查
if c.Method() == "GET" || c.Method() == "HEAD" {
return c.Next()
}
// fasthttp 不允许重复读 Body,必须一次性判断
body := c.Body()
if len(body) > maxBytes {
return c.Status(fiber.StatusRequestEntityTooLarge).
SendString("request body too large")
}
return c.Next()
}
}- 把它挂到特定路由前:
app.Post("/upload", bodyLimitMiddleware(50*1024*1024), uploadHandler) - 别在中间件里调
c.BodyParser()或c.JSON()—— 那会提前消费 body,导致后续 handler 拿不到数据 - 这个方案无法防止超大 body 被完整加载进内存;若需流式截断,得结合
fasthttp.RequestCtx.SetMaxRequestBodySize(需访问底层fasthttp实例)
上传文件的大小限制要单独处理
c.FormFile 和 c.SaveFile 不受 BodyLimit 影响,因为 multipart 解析是独立流程。必须显式调用 c.LimitRequestBody 或在中间件中检查 Content-Type: multipart/form-data 并解析 boundary 前的 header 部分。
- 推荐做法:在上传路由 handler 开头加
if err := c.LimitRequestBody(20 * 1024 * 1024); err != nil { return c.Status(fiber.StatusRequestEntityTooLarge).SendString(...) } -
c.LimitRequestBody是 Fiber v2.49+ 提供的专用方法,内部调用fasthttp的流控机制,比手动读c.Body()更安全 - 如果用的是老版本 Fiber(c.Context().SetMaxRequestBodySize(需类型断言到
*fasthttp.RequestCtx)
实际部署时最容易被忽略的是:multipart 上传和 JSON 请求的限流逻辑完全隔离,必须分别覆盖,否则攻击者会绕过 BodyLimit 直接发超大 form-data。


















