必须在 c.FormFile 前用 http.MaxBytesReader 包装请求体,因 Fiber 无全局上传大小限制,未前置拦截时恶意用户可发送超大请求,Go 的 multipart 解析器会在首次访问时隐式调用 ParseMultipartForm(32

必须在 c.FormFile 前用 http.MaxBytesReader 包装请求体
Fiber 本身不提供上传大小的全局钩子,c.FormFile 调用后若未前置拦截,恶意用户可发送 10GB 请求——Go 的 multipart 解析器会在首次访问时隐式调用 ParseMultipartForm(32 (默认 32MB 内存阈值),但此时请求体早已开始读取,<code>MaxBytesReader 必须出现在 handler 最顶部。
错误写法:c.FormFile 或 c.ParseForm 先执行,再包装 c.Request().Body;正确顺序只有一条:先换 Body,再做任何表单操作。
r.Body = http.MaxBytesReader(c.Context(), r.Body, 10(10MB 总请求体上限,含所有字段+文件)- 该限制包含文本字段值、多个文件字节总和,不是“仅文件”
- 若业务允许 5 个文件 × 2MB,需预留额外空间给文本字段(如标题、描述等),建议设为 12–15MB
c.FormFile 返回的 file.Size 只能用于二次校验,不能替代流控
file.Size 来自 multipart boundary 解析出的元数据,客户端可任意伪造。攻击者发一个声称 Size: 1024 但实际是 5GB 的文件,c.FormFile 仍会返回句柄,后续 c.SaveFile 或 io.Copy 就会触发完整读取——所以 MaxBytesReader 是唯一前置防线,file.Size 仅作业务层二次确认。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 显式检查:
if file.Size > 5 - 多文件场景下,遍历
c.MultipartForm().Value["files"]或用c.MultipartForm().File["files"]获取切片后逐个校验 - 注意:
c.MultipartForm()需要先调用c.ParseMultipartForm(32,否则返回 nil
Fiber 中避免误用 app.Use 或中间件导致 MaxBytesReader 失效
app.Use("/upload", middleware) 这类前缀中间件看似方便,但 Fiber 的中间件执行顺序与原生 http.Handler 不同:它在路由匹配后才执行。一旦路由已匹配到 /upload/single,中间件里的 MaxBytesReader 就晚了——因为 c.FormFile 可能在中间件之前就被隐式触发。
立即学习“go语言免费学习笔记(深入)”;
- 必须把
MaxBytesReader放进具体 handler 函数内部,而不是挂到app.Use - 若要用中间件统一处理,得在
app.Use中对所有路径生效,并确保它在任何路由注册前注册(即最顶层) - 更稳妥的做法:每个上传 handler 单独写,开头固定三行:
r := c.Request(); r.ResetBody(); r.SetBodyStream(...)不推荐,复杂且易错;直接用http.MaxBytesReader最简洁
使用 c.SaveFile 时注意临时磁盘写入不受 MaxBytesReader 控制
c.SaveFile 底层调用的是 multipart.File.Open() + io.Copy,它依赖 MaxBytesReader 对 Body 的包装生效。但如果在调用前已触发过 c.Body()、c.FormValue 或其他隐式解析,Body 可能已被消费,MaxBytesReader 就失去作用。
- 不要在上传 handler 里调用
c.Body()或c.FormValue("xxx")——它们会触发隐式ParseForm,进而提前读取 body - 文本字段应改用
c.MultipartForm().Value["field"],前提是已显式调用c.ParseMultipartForm - 若必须兼容
application/x-www-form-urlencoded和multipart/form-data,先用c.GetReqHeaders()["Content-Type"]判断类型,再分支处理
c.FormFile 在底层仍走 Go 标准库的 multipart.Reader,而它的流式解析行为不会因框架封装而改变。只要没在第一行就用 http.MaxBytesReader 拦截,后面所有校验都是马后炮。


















