r.parsemultipartform 必须显式调用且需在 r.formvalue 等操作前执行,否则 r.formfile 返回 http.errnotmultipart;maxmemory 设为 0 全落盘易堆积,过小则 i/o 增压,建议根据文件大小合理设置。

r.ParseMultipartForm 必须调,不调就拿不到文件,不是 bug,是设计前提。
为什么 r.FormFile 总返回 http.ErrNotMultipart
现象:前端用了 enctype="multipart/form-data",后端却收不到文件,r.FormFile("file") 直接返回错误或 nil。
根本原因只有两个:
• 没调 r.ParseMultipartForm
• 调了但顺序错了——比如在 r.FormValue 之后才调,此时底层 reader 已被消耗,再调会 panic 或静默失败
• 误用 r.ParseForm() 替代,它对 multipart 完全无效,还可能让后续 ParseMultipartForm 报 http: multipart handled
r.ParseMultipartForm 的 maxMemory 参数怎么设
这个值决定多少字节以内留在内存、超了写哪,直接影响 OOM 风险和 I/O 压力:
• 设为 0:等价于跳过内存缓冲,全部落盘,但临时文件管理失控,易堆积
• 设太小(如 1 即 1MB):小文件也频繁刷盘,I/O 毛刺明显<br>• 设太大(如 <code>500 ):单个 500MB 文件上传就可能吃光内存<br>• 推荐档位:<code>32 (32MB)适合图文类;<code>100 (100MB)含 ZIP/MP4;<code>500 (500MB)仅限专业媒体场景,且必须确认 <code>os.TempDir() 有足够空间和写权限
• 记得加 defer r.MultipartForm.RemoveAll(),否则临时文件和内存不会释放
怎么安全保存上传的文件到磁盘
客户端传来的 Filename 是完全不可信的输入,直接拼路径等于开放任意写入:
• 用 filepath.Base(header.Filename) 剥离路径,再用白名单校验扩展名(如只允 .jpg、.pdf)
• 生成服务端唯一文件名:uuid.New().String() + "." + ext,避免覆盖和猜解
• 创建目录用 os.MkdirAll(uploadDir, 0755),写入用 os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644) 显式控权
• 写入必须流式:io.CopyN(dst, src, maxFileSize) 限制最大写入量,防恶意膨胀
• 写完立刻 dst.Sync() 确保落盘,再 dst.Close(),同时别忘 defer f.Close() 释放句柄,否则并发时容易触发 too many open files
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











