应使用http.Request.FormFile解析multipart/form-data上传文件,避免手动读取body;服务端须校验Content-Type、文件头魔数及大小,ParseMultipartForm需提前设置。
使用 http.Request.FormFile 获取前端提交的文件,它会自动解析 multipart/form-data 请求体。注意不要直接用 req.MultipartReader() 或手动读取 body,否则可能破坏表单其他字段的解析。
示例代码:
file, header, err := r.FormFile("upload")
if err != nil {
http.Error(w, "文件未选择或解析失败", http.StatusBadRequest)
return
}
defer file.Close()
仅靠前端 accept 或文件后缀名无法保证安全,必须在服务端校验:
image/jpeg、image/png,但需注意 MIME 类型由客户端提供,不可全信file.Read() 读前 512 字节,调用 http.DetectContentType() 或比对已知魔数(如 PNG 是 89 50 4E 47)r.ParseMultipartForm(32 (32MB),防止内存耗尽;再结合 header.Size 做二次判断
["jpg", "jpeg", "png", "pdf"]),从 header.Filename 提取后缀并小写标准化,不依赖 header.Header.Get("Content-Type")
避免将用户控制的文件名直接用于磁盘路径,防止路径遍历(如 ../../etc/passwd)和覆盖系统文件:
uuid.New().String())或哈希(sha256.Sum256(fileBytes).Hex())生成唯一文件名"./uploads/"),拼接时用 filepath.Join(uploadDir, safeName),禁止拼接原始 filenamechmod 755 uploads/),Web 服务器不直接提供该目录的 HTTP 访问除基础校验外,还需主动防御典型风险:
"../" 或绝对路径;禁用符号链接解析pdfinfo、libreoffice --headless)做轻量解析,或使用专用库(unioffice)验证结构合法性
(如预签名 URL),避免长连接阻塞