Go开发API如何检测multipart/form-data多文件并拒绝多附件上传
问题根因
现有代码的核心问题有两点:
multipart.Reader的Part是流式读取的,当你调用NextPart()获取下一个Part时,上一个Part的IO流会直接被废弃,无法再读取内容,所以循环迭代完所有Part再回头读第一个Part的内容必然是空的- 没有对Part的合法性(是否携带文件名/表单键)做校验,也没有过滤非文件类的普通form字段Part
可行解决方案
处理逻辑调整为:先取第一个合法文件Part,保留流可用的同时,直接检查是否存在下一个Part,如果存在直接抛出多文件错误。示例代码如下:
import ( "io" "mime/multipart" "errors" ) // 你的处理函数 func handleUpload(reader *multipart.Reader, r *http.Request) (*storeRequest, error) { // 先取第一个Part part, err := reader.NextPart() if err != nil { if err == io.EOF { return nil, errors.New("no file uploaded") } return nil, err } defer part.Close() // 校验Part合法性:判断是否有文件名或者表单键,可根据你的业务规则调整 if part.FileName() == "" && part.FormName() == "" { return nil, errors.New("file missing key or name") } // 立刻检查是否存在下一个Part,只要有就直接返回多文件错误,不需要读取后续内容 nextPart, err := reader.NextPart() if err != io.EOF { if nextPart != nil { _ = nextPart.Close() // 主动关闭避免资源泄漏 } return nil, errors.New("too many files") } // 此时确认只有一个合法文件Part,直接使用即可 req := storeRequest{ Data: part, FileName: r.URL.Path, // 注意你原代码的FileNAme拼写错误,这里修正为FileName } return req, nil }
补充说明
- 如果你的业务需要支持普通form字段和文件同时上传,只需要在取第一个Part的时候,过滤掉非文件的Part(判断
FileName()是否为空),直到找到第一个文件Part之后再检查是否有第二个文件Part即可 - 若需要持久化存储文件内容,可直接在获取第一个Part后调用
io.ReadAll(part)读取全部字节保存,不需要依赖流的后续可用性
内容的提问来源于stack exchange,提问作者Tim Potts
相关产品推荐
相关产品推荐

