c.formfile能正确解析multipart文件,而c.postform仅处理文本字段、无法获取文件;必须确保字段名严格匹配、避免重复调用、校验错误而非nil值,并安全重命名及保存文件。

必须用 c.FormFile,不能用 c.PostForm 或手动读 c.Request.Body——后者根本拿不到文件内容,只会返回空或 panic。
为什么 c.PostForm("file") 拿不到上传的文件
c.PostForm 只解析表单里的文本字段(比如 name、email),对 <input type="file"> 这类字段完全无视。它不触发 multipart 解析,也不消耗请求 body,所以你调了十次 c.PostForm("file") 都只得到空字符串。
-
c.FormFile("avatar")才真正触发 multipart 解析,并返回*multipart.FileHeader - 字段名必须和前端
FormData.append("avatar", file)或 HTML 表单中name="avatar"完全一致,大小写敏感 - 同一个字段名重复调用
c.FormFile第二次会返回nil, error,因为 body 已被消费
c.FormFile 后怎么安全保存文件
c.SaveUploadedFile 看起来方便,但直接拼路径(如 "./uploads/" + file.Filename)有严重风险:路径遍历(../../etc/passwd)、同名覆盖、无目录检查。
- 先用
securejoin.SecureJoin("uploads", sanitizeFilename(header.Filename))生成安全路径 - 确保目标目录存在:
os.MkdirAll(filepath.Dir(dst), 0755) - 若需校验内容(如图片尺寸、XML 格式),得先
file.Open()获取io.ReadCloser,再流式处理,不能跳过这步直接 save -
c.SaveUploadedFile内部就是io.Copy,没做任何校验或过滤,慎用于生产环境
curl 测试时 Content-Type 不能手设
用 curl -F "avatar=@photo.jpg" 时,curl 自动设置 Content-Type: multipart/form-data; boundary=...。如果你额外加 -H "Content-Type: application/json",Gin 就完全无法解析表单,c.FormFile 必然失败,报 http: no such file 或 400。
- 删掉所有手动指定的
Content-Type头,让 curl 自己生成 - 混合传参时(文件 + 文本字段),全部用
-F:curl -F "avatar=@a.png" -F "desc=hello" - 后端用
c.PostForm("desc")拿文本字段,c.FormFile("avatar")拿文件,二者互不干扰
真正麻烦的不是“怎么传”,而是“怎么防”。文件名清洗、目录隔离、流式校验、反向代理同步调参——这些漏掉任意一环,上线后都可能变成安全漏洞或服务中断点。











