github.com/qiniu/go-sdk/v7@v7.27.0/sandbox/multipart.go (about) 1 package sandbox 2 3 import ( 4 "fmt" 5 "io" 6 "mime/multipart" 7 "net/textproto" 8 "path/filepath" 9 "strings" 10 ) 11 12 // multipartFileWriter 封装 multipart 文件上传的 writer。 13 type multipartFileWriter struct { 14 w *multipart.Writer 15 } 16 17 // newMultipartWriter 创建一个写入到 w 的 multipartFileWriter。 18 func newMultipartWriter(w io.Writer) *multipartFileWriter { 19 return &multipartFileWriter{w: multipart.NewWriter(w)} 20 } 21 22 // contentType 返回 multipart 的 Content-Type 头。 23 func (m *multipartFileWriter) contentType() string { 24 return m.w.FormDataContentType() 25 } 26 27 // writeFile 将文件数据写入 multipart body。 28 func (m *multipartFileWriter) writeFile(fieldName, fileName string, data []byte) error { 29 part, err := m.w.CreateFormFile(fieldName, filepath.Base(fileName)) 30 if err != nil { 31 return err 32 } 33 _, err = part.Write(data) 34 return err 35 } 36 37 // writeFileFullPath 将文件数据写入 multipart body,part filename 使用完整路径。 38 // 用于批量上传场景,服务端从 part filename 获取文件路径。 39 // 不使用 CreateFormFile,因为它会对 filename 执行 filepath.Base()。 40 func (m *multipartFileWriter) writeFileFullPath(fieldName, fullPath string, data []byte) error { 41 h := make(textproto.MIMEHeader) 42 h.Set("Content-Disposition", fmt.Sprintf(`form-data; name="%s"; filename="%s"`, escapeQuotes(fieldName), escapeQuotes(fullPath))) 43 h.Set("Content-Type", "application/octet-stream") 44 part, err := m.w.CreatePart(h) 45 if err != nil { 46 return err 47 } 48 _, err = part.Write(data) 49 return err 50 } 51 52 var quoteEscaper = strings.NewReplacer("\\", "\\\\", `"`, "\\\"") 53 54 // escapeQuotes 转义字符串中的反斜杠和双引号,用于 Content-Disposition 头部。 55 func escapeQuotes(s string) string { 56 return quoteEscaper.Replace(s) 57 } 58 59 // close 关闭 multipart writer。 60 func (m *multipartFileWriter) close() error { 61 return m.w.Close() 62 }