我可以在Go中使用Content-Type:multipart / form-data进行发布吗?

时间:2017-06-01 08:30:40

标签: http go

如何使用Content-Type POST一个API:multipart / form-data,[] byte参数和字符串参数?我试过了,但它失败了。

错误讯息:

details: "[301 301 Moved Permanently]<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n<html>\r\n301 Moved Permanently\r\n<body bgcolor=\"white\">\r\n301 Moved Permanently\r\n<p>The requested resource has been assigned a new permanent URI.</p >\r\n<hr/>Powered by Tengine/2.1.0</body>\r\n</html>\r\n"

转到代码:

func NewPost2(url string) ([]byte, error) {
    m := make(map[string]interface{}, 0)
    m["fileName"] ="good"
    m["name"] = Base64ToByte("/9j/4AAQSkZJRgABAQEAeAB4AAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAABAAEDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDHooor+wD+Zz//2Q==")
b, _ := json.Marshal(m)

    httpReq, err := http.NewRequest("POST", url, bytes.NewBuffer(b))
    httpReq.Header.Set("Content-Type", "multipart/form-data;charset=UTF-8")

    client := &http.Client{}
    resp, err := client.Do(httpReq)
    if err != nil {
        return nil, err
    }

    defer resp.Body.Close()

    if resp.StatusCode < 200 || resp.StatusCode >= 300 {
        b, _ := ioutil.ReadAll(resp.Body)
        return nil, fmt.Errorf("[%d %s]%s", resp.StatusCode, resp.Status, string(b))
    }

    respData, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return nil, err
    }

    return respData, nil
}

3 个答案:

答案 0 :(得分:2)

现在,我对分享我的解决方案的心情非常满意

func NewPostFile(url string, paramTexts map[string]interface{}, paramFile FileItem) ([]byte, error) {
// if paramFiles ==nil {
//  return NewPost(url,paramTexts,header,transport)
// }

bodyBuf := &bytes.Buffer{}
bodyWriter := multipart.NewWriter(bodyBuf)

for k, v := range paramTexts {
    bodyWriter.WriteField(k, v.(string))
}
fileWriter, err := bodyWriter.CreateFormFile(paramFile.Key, paramFile.FileName)
if err != nil {
    fmt.Println(err)
    //fmt.Println("Create form file error: ", error)
    return nil, err
}
fileWriter.Write(paramFile.Content)
contentType := bodyWriter.FormDataContentType()
bodyWriter.Close()
fmt.Println(bodyBuf.String())

resp, err := http.Post(url, contentType, bodyBuf)
if err != nil {
    return nil, err
}
defer resp.Body.Close()
fmt.Println(resp)

if resp.StatusCode < 200 || resp.StatusCode >= 300 {
    b, _ := ioutil.ReadAll(resp.Body)
    return nil, fmt.Errorf("[%d %s]%s", resp.StatusCode, resp.Status, string(b))
}
respData, err := ioutil.ReadAll(resp.Body)
if err != nil {
    return nil, err
}
fmt.Println(string(respData))
return respData, nil

}

type FileItem struct {
Key      string //image_content
FileName string //test.jpg
Content  []byte //[]byte

}

答案 1 :(得分:0)

在301响应中,新网址在响应的标题中指定,而不是在其正文中

(见https://en.wikipedia.org/wiki/HTTP_301

尝试打印:

resp.Header["Location"]

如果您将此错误作为最终回复,这也意味着http.Client选择不遵循此重定向。

doc表示客户的dafult政策是要跟进10次重定向。

为了调试重定向,您可以编写自己的CheckRedirect函数,例如可以打印网址序列

答案 2 :(得分:0)

我将多部分代码包装在一个函数中,因为您需要先Close 可以提出要求。另外我的方法是使用 @ 作为启发式,类似于 卷曲 [1]:

package main

import (
   "bytes"
   "io"
   "mime/multipart"
   "os"
   "strings"
)

func createForm(form map[string]string) (string, io.Reader, error) {
   body := new(bytes.Buffer)
   mp := multipart.NewWriter(body)
   defer mp.Close()
   for key, val := range form {
      if strings.HasPrefix(val, "@") {
         val = val[1:]
         file, err := os.Open(val)
         if err != nil { return "", nil, err }
         defer file.Close()
         part, err := mp.CreateFormFile(key, val)
         if err != nil { return "", nil, err }
         io.Copy(part, file)
      } else {
         mp.WriteField(key, val)
      }
   }
   return mp.FormDataContentType(), body, nil
}

示例:

package main
import "net/http"

func main() {
   form := map[string]string{"profile": "@portrait.jpg", "name": "John"}
   ct, body, err := createForm(form)
   if err != nil {
      panic(err)
   }
   http.Post("https://stackoverflow.com", ct, body)
}
  1. https://curl.se/docs/manpage.html#-F