如何在Golang中实现文件上传功能_处理多文件和限制大小

Go文件上传需先调用ParseMultipartForm设置内存阈值(如33554432),再用FormFile获取文件流;统一通过r.MultipartForm.File["files"]处理单/多文件;严格校验Size与DetectContentType识别的真实MIME类型;保存时须路径过滤、UUID重命名、权限控制。

在 Go 中实现文件上传,关键是用好 http.RequestParseMultipartFormFormFile 方法,配合合理的校验与存储逻辑。多文件和大小限制不是额外功能,而是解析和校验环节的自然延伸。

正确解析 multipart 表单并设置内存阈值

Go 默认只将小文件读入内存,大文件会临时写入磁盘。必须显式调用 ParseMultipartForm 并传入最大内存限制(单位字节),否则 FormFile 可能返回空或 panic。

  • 建议设为 32MB(33554432)以内,兼顾性能与安全
  • 若不调用该方法,r.MultipartForm 为 nil,FormFile 将无法获取文件
  • 错误示例:r.ParseMultipartForm(0) 会导致全部写入临时磁盘,失去内存控制

单文件与多文件上传的统一处理方式

前端用 ,后端用 r.MultipartForm.File["files"] 获取文件切片,无需区分单/多——它天然返回 []*multipart.FileHeader

  • 遍历该切片,对每个 FileHeader 调用 r.FormFile 打开流
  • FileHeader.Size 是文件原始大小(未解压、未编码),可用于前置校验
  • 不要依赖 len(fileBytes) 校验大小——大文件不能全读进内存

严格校验文件大小与类型(不只看后缀)

仅检查扩展名极易被绕过。应在读取前用 FileHeader.Size 拦截超限文件,并用 http.DetectContentType 验证真实 MIME 类型。

  • 例如:限制单文件 ≤ 10MB,总上传 ≤ 50MB,直接在循环中累加校验
  • 打开文件流后,读取前 512 字节送入 http.DetectContentType,比对白名单(如 image/jpeg, application/pdf
  • 校验失败立即关闭当前文件句柄,继续处理下一个,避免阻塞

安全保存文件:重命名 + 路径过滤 + 权限控制

用户提交的 Filename 不可信。必须剥离路径、生成唯一名、限定保存目录,且禁止执行权限。

  • filepath.Base(header.Filename) 去掉恶意路径(如 ../../../etc/passwd
  • uuid.New().String() + ext 重命名,避免覆盖和猜解
  • 保存前检查目标目录是否存在,用 os.MkdirAll(dir, 0755) 创建;写入时用 os.O_CREATE|os.O_WRONLY|os.O_EXCL 防覆盖