Golang实现请求http post接口上传文件demo及注意事项

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
	}
	...

注意事项

  1. 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)
}
  1. 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)
	...
  1. 设置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
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值