必须先调用GetFile再调用SaveToFile,否则header.Filename为空或随机;需用path.Base清洗文件名防路径遍历,中文名应统一UTF-8编码;MaxMemory≥MaxUploadSize时强制走磁盘缓存,降低小文件上传性能。

Beego 中 GetFile 和 SaveToFile 的正确调用顺序
直接调用 SaveToFile 前必须先调用 GetFile,否则 header.Filename 为空或为随机名。Beego 不会在请求解析阶段自动提取文件元信息,而是延迟到你显式调用 GetFile("field_name") 时才从 multipart.Form 中取出对应字段的 *multipart.FileHeader。
常见错误现象:上传后服务器保存的文件名为 upload_123456 或空字符串,实际是没取到 header.Filename 就拼路径。
-
GetFile返回三个值:*os.File(可读流)、*multipart.FileHeader(含Filename、Size、Header)、error,三者缺一不可 - 必须在
SaveToFile之前读取header.Filename,因为SaveToFile内部不校验或修正文件名 - 若表单字段名不是
"file"(比如前端用name="myfile"),GetFile参数必须严格匹配,否则返回nil, nil, error
避免中文文件名乱码与路径安全问题
Beego 默认不处理 header.Filename 的编码,原始值可能为 UTF-8 或 GBK 编码的字节序列,直接拼进文件路径会导致 open /path/测试.jpg: no such file or directory 类错误——本质是操作系统无法识别该路径名。
更隐蔽的风险是路径遍历:header.Filename 可被客户端篡改为 ../../etc/passwd,若不做清理就拼进 SaveToFile 的第二参数,可能写入任意目录。
- 用
path.Base(header.Filename)截掉路径部分,只保留原始文件名 - 对文件名做白名单过滤:允许字母、数字、下划线、短横线、点号,拒绝控制字符和路径分隔符
- 中文名建议统一转为 UTF-8 并保持原样(Linux/macOS 支持良好),Windows 部署时需确认 Go 运行时环境支持 UTF-16 转码(Go 1.16+ 基本无问题)
- 不要依赖
header.Filename构造完整路径,SaveToFile第二个参数应为「确定安全的绝对或相对路径 + 经清洗的文件名」
MaxMemory 和 MaxUploadSize 的协同作用
这两个配置共同决定上传流程是否走内存还是临时磁盘,且存在隐含大小关系约束:如果 MaxMemory >= MaxUploadSize,Beego 会忽略 MaxMemory 设置,强制全部走磁盘缓存,这会显著拖慢小文件上传速度。
典型错误配置:MaxUploadSize = 10 (10MB),但 <code>MaxMemory = 1 (16MB),此时所有上传都进内存,一旦并发高容易 OOM。
- 推荐设置:
MaxMemory = 32 (32MB),<code>MaxUploadSize = 100 (100MB),确保中小文件走内存,大文件落磁盘 - 配置位置:可在
main.go中写web.MaxMemory = 32 ,或在 <code>conf/app.conf加maxmemory = 33554432 - 注意单位:Beego 所有 size 配置都是字节数,不是字符串如
"32MB";1 是 1MB,<code>1 是 16MB - 超出
MaxUploadSize会直接返回 HTTP 413,不会进入 Controller,所以日志里看不到GetFile调用痕迹
静态文件下载必须绕过浏览器自动渲染
直接通过 SetStaticPath 暴露文件路径(如 /staticfiles/xxx.pdf)会导致 PDF、PNG、TXT 等类型在浏览器中打开而非下载——这不是 Beego 的 bug,而是 HTTP Content-Type 和浏览器策略决定的。
真正可控的下载方式是用 Ctx.Output.Download,它会强制设置 Content-Disposition: attachment 头,并允许指定下载时的文件名。
- 用法示例:
f, _ := os.Open("/path/to/file.zip"); defer f.Close(); c.Ctx.Output.Download(f, "report_20260821.zip") - 注意
Download第二个参数是「用户看到的文件名」,不是服务器路径;它不影响服务端文件存储名 - 如果文件在
static/下且路径已知,可用http.ServeFile替代,但需手动设 header,不如Download简洁 - 不要在 Download 前调用
Ctx.WriteString或写任何响应体,否则会触发 “write on hijacked connection” 错误
最易被忽略的一点:上传成功后返回的 JSON 或 HTML 中若含中文文件名,必须确保整个 HTTP 响应的 Content-Type 带 ; charset=utf-8,否则前端 JS 解析 responseText 可能乱码——Beego 默认不加这个 charset,需手动 c.Ctx.ResponseWriter.Header().Set("Content-Type", "application/json; charset=utf-8")。


















