Demo

transport := &http.Transport{

DisableKeepAlives: true,

}

if proxy != "" {

proxyUrl, _ := nUrl.Parse(proxy)

proxyFunc := http.ProxyURL(proxyUrl)

transport.Proxy = proxyFunc

}

client := &http.Client{Transport: transport}

bodyBuf := &bytes.Buffer{}

bodyWriter := multipart.NewWriter(bodyBuf)

//设置非文件入参k-v格式

for key, val := range params {

err0 := bodyWriter.WriteField(key, fmt.Sprint(val))

if err0 != nil {

return

}

}

//设置文件入参

for key, file := range fileparams {

fileWriter, err0 := bodyWriter.CreateFormFile(key, file.Filename)

// 把文件流写入到缓冲区里去

written, err0 := io.Copy(fileWriter, file.File)

if err0 != nil {

return

}

}

// 一定要记着关闭

err0 := bodyWriter.Close()

if err0 != nil {

return

}

//创建请求

req, err0 := http.NewRequest(http.MethodPost, meta.url, bodyBuf)

if err != nil {

return

}

//添加头

for key, val := range headers {

req.Header.Set(key, val)

}

req.Header.Set("Content-Type", bodyWriter.FormDataContentType())

// 发送post请求

response, err0 := client.Do(req)

if err0 != nil {

return

}

defer response.Body.Close()

//处理响应

body, err0 := ioutil.ReadAll(response.Body)

if err0 != nil {

return

}

...

注意事项

golang 官方函数CreateFormFile中 会自动设置文件字段的Content-Type,如果请求的接口对Content-Type有要求,需要注意此函数是否适用,如果不适用可自定义一个方法实现

// CreateFormFile is a convenience wrapper around CreatePart. It creates

// a new form-data header with the provided field name and file name.

func (w *Writer) CreateFormFile(fieldname, filename string) (io.Writer, error) {

h := make(textproto.MIMEHeader)

h.Set("Content-Disposition",

fmt.Sprintf(`form-data; name="%s"; filename="%s"`,

escapeQuotes(fieldname), escapeQuotes(filename)))

h.Set("Content-Type", "application/octet-stream")

return w.CreatePart(h)

}

io.Read、io.Copy ,文件使用此方法读取完成后,offset在文件末尾,如果想再次读取文件内容,需要先使用Seek函数重置偏移位为文件初始位置,再进行读取;否则 再次读到的文件内容为空! 比如有个应用场景是先计算文件的md5,再将文件、md5作为入参请求http post接口。

hash := md5.New()

if _, err := io.Copy(hash, file); err != nil {

return 0

}

md5sum := hex.EncodeToString(hash.Sum(nil))

//!!!一定要重置

file.Seek(0, io.SeekStart)

...

fileWriter, err0 := bodyWriter.CreateFormFile(key, file.Filename)

written, err0 := io.Copy(fileWriter, file.File)

...

设置Content-Type

req.Header.Set("Content-Type", bodyWriter.FormDataContentType())

// FormDataContentType returns the Content-Type for an HTTP

// multipart/form-data with this Writer's Boundary.

func (w *Writer) FormDataContentType() string {

b := w.boundary

// We must quote the boundary if it contains any of the

// tspecials characters defined by RFC 2045, or space.

if strings.ContainsAny(b, `()<>@,;:\"/[]?= `) {

b = `"` + b + `"`

}

return "multipart/form-data; boundary=" + b

}

参考阅读

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。