ctx.FormFile("file") 返回 *multipart.FileHeader,含 Filename、Size 等字段,适用于单文件上传,需确保表单 enctype="multipart/form-data" 且 name 匹配;Size 为字节数,Filename 可能含路径需净化,MIME 类型须校验文件头而非依赖 Header。

如何用 ctx.FormFile() 获取上传文件名和大小
直接调用 ctx.FormFile("file") 是最常用方式,它返回 *multipart.FileHeader,里面含 Filename、Size 和 Header 等关键字段。注意:这个函数只适用于单文件上传表单字段,且必须是 type="file" 的 input,name 属性值要和参数一致。
常见错误是传错字段名导致返回 nil, nil,或者没加 enctype="multipart/form-data" 导致 ctx.FormFile() 一直返回空。另外,Size 是字节数,不是人类可读格式,需要自己转 KB/MB。
- 确保 HTML 表单包含
enctype="multipart/form-data" - 字段名(如
"file")必须和前端<input name="file">完全一致,区分大小写 -
FileHeader.Size在文件为空时为 0,但不表示上传失败,需结合Filename是否为空判断
ctx.MultipartForm() 适合多文件或混合表单数据场景
当一次请求同时上传多个文件、或文件 + 普通文本字段(如 title、desc)时,ctx.MultipartForm() 更合适。它返回 *multipart.Form,其中 Value 存文本字段,File 是 map[string][]*multipart.FileHeader。
相比 FormFile(),它不自动解析文件流,只是结构化原始 multipart 数据,性能开销略小,也避免重复解析。但要注意:调用后所有文件都已读入内存(或临时文件),不能再用 FormFile() 再取同一字段。
立即学习“go语言免费学习笔记(深入)”;
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 获取多个同名文件用
form.File["files"],返回切片,遍历即可 - 文本字段从
form.Value["title"]取,注意它是[]string,通常取[0] - 如果只用
FormFile()取了某个字段,再调MultipartForm()可能 panic:already parsed
文件扩展名和 MIME 类型不能只信 Filename 或 Header
FileHeader.Filename 是客户端传来的原始文件名,可能带路径(如 ../etc/passwd)、空格或非法字符;FileHeader.Header.Get("Content-Type") 是浏览器猜的 MIME 类型,可被伪造。真实类型必须靠读取文件头(magic bytes)判断。
比如用户上传 .jpg 但实际是 .exe,仅靠扩展名或 header 会误判。Gin 不提供内置校验,得自己用 mime.TypeByExtension() 做初步过滤,再用 http.DetectContentType() 或第三方库(如 golang.org/x/net/html 不适用,推荐 github.com/h2non/filetype)检测二进制头。
- 先用
filepath.Base(fh.Filename)提取纯文件名,再用strings.ToLower(filepath.Ext(name))取扩展名 -
fh.Header.Get("Content-Type")可能为空或不可信,不要单独依赖它做类型限制 - 若要求严格,打开
fh.Open()读前 512 字节送入filetype.MatchReader()校验
大文件上传时 Size 和内存占用容易被忽略
FileHeader.Size 是客户端声明的大小,不代表服务端实际接收量——网络中断、客户端提前关闭都会导致实际读取小于该值。更关键的是:FormFile() 或 MultipartForm() 默认把整个文件读进内存(除非配置了 MaxMultipartMemory),超限会直接 400 错误。
Gin 默认 MaxMultipartMemory = 32 (32MB),超出就报 <code>http: request body too large。调整它要在初始化路由前设置:gin.SetMode(gin.ReleaseMode); r := gin.Default(); r.MaxMultipartMemory = 100 。但单纯调大内存不是长久之计,大文件应考虑流式处理或对接对象存储。
-
fh.Size是声明值,最终读取长度以io.Copy()实际字节数为准 - 调大
MaxMultipartMemory会增加 GC 压力,线上环境建议设为业务最大合理值,而非无上限 - 真正处理 GB 级文件时,别用
fh.Open()全读内存,改用ctx.Request.MultipartReader()流式转发

















