r.ParseMultipartForm 默认内存限制为32KB,超出即panic;需在调用前显式设置更大值,如r.ParseMultipartForm(10 << 20)。

为什么 r.ParseMultipartForm 会 panic: multipart: NextPart: bufio: buffer full
这是最常遇到的阻塞点:Go 默认只分配 32KB 内存来读取 multipart body,超出就直接 panic。不是你代码写错了,是没显式设置上限。
- 必须在调用
r.ParseMultipartForm前设置r.ParseMultipartForm(32 (比如 32MB),数值单位是字节 - 这个值不能设太小(否则上传大文件失败),也不能无脑设成
math.MaxInt64(可能被恶意构造的超大表单耗尽内存) - 如果只处理纯文本字段、几乎不传文件,设
1 (1MB)足够;含文件上传务必按业务预期最大体积预估
formFile 和 FormFile 的区别在哪?什么时候该用哪个
别被名字迷惑:formFile 是 http.Request 方法,FormFile 是 *multipart.Form 字段——但后者根本不存在。真正能用的只有 req.FormFile 和 req.MultipartReader。
-
req.FormFile("<code>avatar") 直接返回*multipart.FileHeader+io.ReadCloser,适合单个文件上传场景 - 多个同名文件(如多图上传)必须用
req.MultipartReader()配合reader.NextPart()迭代,FormFile只取第一个 - 如果先调了
req.ParseMultipartForm,再调FormFile会返回nil, err(因为 body 已被读过一遍,底层 reader 已 EOF)
如何安全读取并校验上传的文件名和内容类型
浏览器提交的 filename 和 Content-Type 完全不可信,服务端必须重新检查。
- 从
*multipart.FileHeader拿到的Filename是客户端传的,可能含路径遍历(如../../etc/passwd),要用filepath.Base截取干净文件名 -
Header.Get("Content-Type")可被伪造,真实 MIME 类型得靠读取文件头几个字节,用net/http.DetectContentType或第三方库如gabriel-vasile/mimetype - 不要依赖扩展名判断类型(
.jpg不代表就是 JPEG),也不要仅靠Content-Type做权限控制
解析后怎么拿到非文件字段(比如 user_id、description)
很多人以为 ParseMultipartForm 后就能直接用 req.FormValue,其实不一定——取决于字段是否被归入 form 还是留在原始 body 流里。
立即学习“go语言免费学习笔记(深入)”;
- 必须先调
req.ParseMultipartForm,否则req.FormValue返回空字符串 - 调用后,所有非文件字段会自动填充进
req.PostForm(即req.Form),此时req.FormValue("<code>user_id") 才有效 - 如果字段名带点或中括号(如
user.profile.name),Go 默认不解析嵌套结构,得手动从req.MultipartReader中逐个NextPart并匹配Part.Header.Get("Content-Disposition")
req.MultipartReader() 和 req.ParseMultipartForm() 互斥,且都只能调一次**。选错路径会导致后续读取失败或数据丢失,而错误信息往往只报 “unexpected EOF” 或 “invalid memory address”,看不出根源。










