多部分文件字段无法读取

huangapple go评论107阅读模式
英文:

Multipart file field is unreadable

问题

我正在尝试将照片上传到Twitter。我创建了一个multipart writer,并使用它创建了一个名为media的文件字段,但是当我将请求发送到Twitter时,它始终回复缺少media字段。我是否漏掉了什么?以下是我的代码:

  1. f, err := os.Open("/Users/nikos/Desktop/test.png")
  2. errored:
  3. if nil != err {
  4. fmt.Println(err)
  5. return
  6. }
  7. var img = new(bytes.Buffer)
  8. enc := base64.NewEncoder(base64.StdEncoding, img)
  9. _, err = io.Copy(enc, f)
  10. if nil != err {
  11. goto errored
  12. }
  13. body := new(bytes.Buffer) // Multipart body
  14. writer := multipart.NewWriter(body)
  15. cl, err := twitter.OauthClient.MakeHttpClient(&oauth.AccessToken{
  16. Token: "xxx",
  17. Secret: "yyy",
  18. })
  19. err = writer.WriteField("media_data", img.String()) // 图片的base64版本(我尝试过二进制和base64版本,都不起作用)
  20. if nil != err {
  21. goto errored
  22. }
  23. part, err := writer.CreateFormFile("media", "test.png") // 实际的二进制文件被分成多部分,并命名为media。
  24. if nil != err {
  25. goto errored
  26. }
  27. _, err = io.Copy(part, f)
  28. if nil != err {
  29. goto errored
  30. }
  31. req, err := http.NewRequest("POST",
  32. "https://upload.twitter.com/1.1/media/upload.json",
  33. body)
  34. if nil != err {
  35. goto errored
  36. }
  37. res, err := cl.Do(req)
  38. if nil != err {
  39. goto errored
  40. }
  41. // Twitter回复说没有附加名为media的字段
  42. _, err = io.Copy(os.Stdout, res.Body)
  43. fmt.Println(res)
  44. if nil != err {
  45. goto errored
  46. }

希望能对你有所帮助!

英文:

I am trying to upload photos to Twitter. I created a multipart writer and creating a file field using that named media but when I send my request to Twitter it keeps responding missing media field.
Am I missing something?
Here is my code

  1. f, err := os.Open("/Users/nikos/Desktop/test.png")
  2. errored:
  3. if nil != err {
  4. fmt.Println(err)
  5. return
  6. }
  7. var img = new(bytes.Buffer)
  8. enc := base64.NewEncoder(base64.StdEncoding, img)
  9. _, err = io.Copy(enc, f)
  10. if nil != err {
  11. goto errored
  12. }
  13. body := new(bytes.Buffer)//Multipart body
  14. writer := multipart.NewWriter(body)
  15. cl, err := twitter.OauthClient.MakeHttpClient(&oauth.AccessToken{
  16. Token: "xxx",
  17. Secret: "yyy",
  18. })
  19. err = writer.WriteField("media_data", img.String())//base64 version of the image (i tried both binary and base64 versions neither will work)
  20. if nil != err {
  21. goto errored
  22. }
  23. part, err := writer.CreateFormFile("media", "test.png")//actual binary file multiparted and it is named media.
  24. if nil != err {
  25. goto errored
  26. }
  27. _, err = io.Copy(part, f)
  28. if nil != err {
  29. goto errored
  30. }
  31. req, err := http.NewRequest("POST",
  32. "https://upload.twitter.com/1.1/media/upload.json",
  33. body)
  34. if nil != err {
  35. goto errored
  36. }
  37. res, err := cl.Do(req)
  38. if nil != err {
  39. goto errored
  40. }
  41. //and twitter responds that there is no field attached named media
  42. _, err = io.Copy(os.Stdout, res.Body)
  43. fmt.Println(res)
  44. if nil != err {
  45. goto errored
  46. }

答案1

得分: 2

更新:刚刚查看了Twitter API上传参数。根据你的代码片段,你同时使用了mediamedia_data两个字段。你只需要使用其中一个:

  • 使用base64上传 -> 字段名为media_data
  • 使用原始数据上传 -> 字段名为media

此外,你还需要添加Content-Type头部。

  1. req, err := http.NewRequest("POST",
  2. "https://upload.twitter.com/1.1/media/upload.json",
  3. body)
  4. req.Header.Set("Content-Type", writer.FormDataContentType())
  5. if err := writer.Close(); err != nil {
  6. log.Println(err)
  7. }
  8. // 现在发送http请求

PS:在回答问题时,@cerise-limón在30秒的间隔内添加了评论,还要按照@cerise-limón的建议关闭multipart writer。


在评论中提问:

> Twitter接受application/octet-stream,你可能不需要下面的方法。

使用用户提供的Content-Type添加多部分数据,而不是使用application/octet-stream。基本上,你需要使用与方便包装器相同的实现,只是将其替换为你的内容类型。

  1. writer := multipart.NewWriter(body)
  2. h := make(textproto.MIMEHeader)
  3. h.Set("Content-Disposition", fmt.Sprintf(`form-data; name="%s"; filename="%s"`,
  4. escapeQuotes(fieldname), escapeQuotes(filename)))
  5. h.Set("Content-Type", "image/png")
  6. part, err := writer.CreatePart(h)
  7. // 使用part与之前相同的方式

escapeQuotes的定义来自多部分包。

  1. var quoteEscaper = strings.NewReplacer("\\", "\\\\", `"`, "\\\"")
  2. func escapeQuotes(s string) string {
  3. return quoteEscaper.Replace(s)
  4. }
英文:

Updates: Just referred Twitter API Upload parameter. As per your code snippet you're using both fields media and media_data. You have to use only one -

  • Upload using base64 -> field name is media_data
  • Upload using raw -> field name is media

And, you have to add Content-Type header.

  1. req, err := http.NewRequest("POST",
  2. "https://upload.twitter.com/1.1/media/upload.json",
  3. body)
  4. req.Header.Set("Content-Type", writer.FormDataContentType())
  5. if err := writer.Close(); err != nil {
  6. log.Println(err)
  7. }
  8. // Now fire the http request

PS: While composing an answer, in 30 secs gap, @cerise-limón added comment, also close the multipart writer as mentioned by @cerise-limón.


Asked in the comment:

> Twitter accepts application/octet-stream, you may not need below approach.

Adding multi-part with user supplied Content-Type instead of application/octet-stream. Basically you have to do same implementation as convenience wrapper with your content-type.

  1. writer := multipart.NewWriter(body)
  2. h := make(textproto.MIMEHeader)
  3. h.Set("Content-Disposition", fmt.Sprintf(`form-data; name="%s"; filename="%s"`,
  4. escapeQuotes(fieldname), escapeQuotes(filename)))
  5. h.Set("Content-Type", "image/png")
  6. part, err := writer.CreatePart(h)
  7. // use part same as before

Definition of escapeQuotes from multiple-part package.

  1. var quoteEscaper = strings.NewReplacer("\\", "\\\\", `"`, "\\\"")
  2. func escapeQuotes(s string) string {
  3. return quoteEscaper.Replace(s)
  4. }

huangapple
  • 本文由 发表于 2017年6月19日 05:16:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/44619606.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定