Go Fiber 文件上传核心是 c.FormFile()(单文件)和 c.MultipartForm()(多文件),不可用 c.Body() 或 c.FormValue();需前置设置 SetMaxRequestBodySize,文件名取 header.Filename,用 header.Open() 读取。

Go Fiber 框架处理文件上传,核心靠 c.FormFile()(单文件)和 c.MultipartForm()(多文件),不是 c.Body() 或 c.FormValue() —— 后两者根本拿不到文件内容。
单文件上传:用 c.FormFile(),别手动解析 multipart
单文件最简路径是直接调 c.FormFile("file"),它返回 *multipart.FileHeader,含文件名、大小、头信息,且已校验过 MIME 类型边界。手动读 c.Request().Body() 会破坏 fasthttp 的流式复用机制,还容易漏掉 boundary 解析逻辑。
-
c.FormFile()内部已调用ParseMultipartForm,无需再显式调用;重复调用会 panic - 文件名必须用
header.Filename,别信c.FormValue("filename")—— 前端可能伪造,且 multipart 中 filename 是独立字段 - 打开文件要用
header.Open(),不是os.Open(header.Filename)—— 后者读的是服务端临时路径,不可靠 - 若需限制大小,必须在路由前加中间件调
c.Request().SetMaxRequestBodySize(n),否则大文件会直接 413,FormFile()根本不执行
app.Post("/upload", func(c fiber.Ctx) error {
file, err := c.FormFile("file")
if err != nil {
return c.Status(fiber.StatusBadRequest).SendString("no file received")
}
src, _ := file.Open()
defer src.Close()
<p>dst, _ := os.Create("/tmp/" + file.Filename)
defer dst.Close()
io.Copy(dst, src)
return c.SendStatus(fiber.StatusOK)
})
多文件上传:必须用 c.MultipartForm(),c.FormFile() 不适用
c.FormFile() 只取第一个匹配 name 的文件,多文件场景下它永远只返回一个 —— 即使 HTML 中写了 <input name="files" multiple>,后端也得用 MultipartForm() 才能拿到全部。
-
c.MultipartForm()返回*multipart.Form,其中form.File是map[string][]*multipart.FileHeader,key 是 input 的 name,value 是该 name 下所有文件切片 - 前端
<input type="file" name="photos" multiple>→ 后端查form.File["photos"],不是form.File["file"] - 每个
FileHeader都要单独Open(),不能共用一个src句柄 - 注意
form.Value是普通表单字段(如 description),和文件分开存,别混在一起遍历
app.Post("/uploads", func(c fiber.Ctx) error {
form, err := c.MultipartForm()
if err != nil {
return c.Status(fiber.StatusBadRequest).SendString(err.Error())
}
<p>for <em>, files := range form.File["photos"] {
src, </em> := files.Open()
dst, _ := os.Create("/tmp/" + files.Filename)
io.Copy(dst, src)
src.Close(); dst.Close()
}
return c.SendStatus(fiber.StatusOK)
})
常见错误:HTML name 和后端 key 不一致、没设最大请求体、误用 c.Body()
三个高频坑:一是前端写 name="avatar",后端却查 c.FormFile("file");二是没调 SetMaxRequestBodySize(),大文件直接被 fasthttp 拦截,连 handler 都进不去;三是试图用 c.Body() 读 multipart 数据,结果得到空字节或 panic。
- HTML 中
<input name="docs">→ 后端必须用c.FormFile("docs")或form.File["docs"] -
c.Request().SetMaxRequestBodySize(10 * 1024 * 1024)要放在路由注册前,或在中间件里统一设(推荐) -
c.Body()是原始二进制,但 multipart 已被 fasthttp 解析并消费,再读就是空;想调试原始体只能用c.Context().RequestBodyStream()+ 自定义 parser - 上传失败时,
c.Status(400).SendString()后必须return,Fiber 不会自动中断链路
真正麻烦的从来不是“怎么写”,而是上传过程中临时文件生命周期、磁盘空间监控、恶意文件名过滤(比如 ../../etc/passwd)、以及并发上传时的文件句柄竞争 —— 这些都不在 FormFile 接口里,得自己兜底。


















