英文:
Multipart file field is unreadable
问题
我正在尝试将照片上传到Twitter。我创建了一个multipart writer,并使用它创建了一个名为media的文件字段,但是当我将请求发送到Twitter时,它始终回复缺少media字段。我是否漏掉了什么?以下是我的代码:
f, err := os.Open("/Users/nikos/Desktop/test.png")
errored:
if nil != err {
fmt.Println(err)
return
}
var img = new(bytes.Buffer)
enc := base64.NewEncoder(base64.StdEncoding, img)
_, err = io.Copy(enc, f)
if nil != err {
goto errored
}
body := new(bytes.Buffer) // Multipart body
writer := multipart.NewWriter(body)
cl, err := twitter.OauthClient.MakeHttpClient(&oauth.AccessToken{
Token: "xxx",
Secret: "yyy",
})
err = writer.WriteField("media_data", img.String()) // 图片的base64版本(我尝试过二进制和base64版本,都不起作用)
if nil != err {
goto errored
}
part, err := writer.CreateFormFile("media", "test.png") // 实际的二进制文件被分成多部分,并命名为media。
if nil != err {
goto errored
}
_, err = io.Copy(part, f)
if nil != err {
goto errored
}
req, err := http.NewRequest("POST",
"https://upload.twitter.com/1.1/media/upload.json",
body)
if nil != err {
goto errored
}
res, err := cl.Do(req)
if nil != err {
goto errored
}
// Twitter回复说没有附加名为media的字段
_, err = io.Copy(os.Stdout, res.Body)
fmt.Println(res)
if nil != err {
goto errored
}
希望能对你有所帮助!
英文:
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
f, err := os.Open("/Users/nikos/Desktop/test.png")
errored:
if nil != err {
fmt.Println(err)
return
}
var img = new(bytes.Buffer)
enc := base64.NewEncoder(base64.StdEncoding, img)
_, err = io.Copy(enc, f)
if nil != err {
goto errored
}
body := new(bytes.Buffer)//Multipart body
writer := multipart.NewWriter(body)
cl, err := twitter.OauthClient.MakeHttpClient(&oauth.AccessToken{
Token: "xxx",
Secret: "yyy",
})
err = writer.WriteField("media_data", img.String())//base64 version of the image (i tried both binary and base64 versions neither will work)
if nil != err {
goto errored
}
part, err := writer.CreateFormFile("media", "test.png")//actual binary file multiparted and it is named media.
if nil != err {
goto errored
}
_, err = io.Copy(part, f)
if nil != err {
goto errored
}
req, err := http.NewRequest("POST",
"https://upload.twitter.com/1.1/media/upload.json",
body)
if nil != err {
goto errored
}
res, err := cl.Do(req)
if nil != err {
goto errored
}
//and twitter responds that there is no field attached named media
_, err = io.Copy(os.Stdout, res.Body)
fmt.Println(res)
if nil != err {
goto errored
}
答案1
得分: 2
更新:刚刚查看了Twitter API上传参数。根据你的代码片段,你同时使用了media
和media_data
两个字段。你只需要使用其中一个:
- 使用base64上传 -> 字段名为
media_data
- 使用原始数据上传 -> 字段名为
media
此外,你还需要添加Content-Type
头部。
req, err := http.NewRequest("POST",
"https://upload.twitter.com/1.1/media/upload.json",
body)
req.Header.Set("Content-Type", writer.FormDataContentType())
if err := writer.Close(); err != nil {
log.Println(err)
}
// 现在发送http请求
PS:在回答问题时,@cerise-limón在30秒的间隔内添加了评论,还要按照@cerise-limón的建议关闭multipart writer。
在评论中提问:
> Twitter接受application/octet-stream
,你可能不需要下面的方法。
使用用户提供的Content-Type
添加多部分数据,而不是使用application/octet-stream
。基本上,你需要使用与方便包装器相同的实现,只是将其替换为你的内容类型。
writer := multipart.NewWriter(body)
h := make(textproto.MIMEHeader)
h.Set("Content-Disposition", fmt.Sprintf(`form-data; name="%s"; filename="%s"`,
escapeQuotes(fieldname), escapeQuotes(filename)))
h.Set("Content-Type", "image/png")
part, err := writer.CreatePart(h)
// 使用part与之前相同的方式
escapeQuotes
的定义来自多部分包。
var quoteEscaper = strings.NewReplacer("\\", "\\\\", `"`, "\\\"")
func escapeQuotes(s string) string {
return quoteEscaper.Replace(s)
}
英文:
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.
req, err := http.NewRequest("POST",
"https://upload.twitter.com/1.1/media/upload.json",
body)
req.Header.Set("Content-Type", writer.FormDataContentType())
if err := writer.Close(); err != nil {
log.Println(err)
}
// 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.
writer := multipart.NewWriter(body)
h := make(textproto.MIMEHeader)
h.Set("Content-Disposition", fmt.Sprintf(`form-data; name="%s"; filename="%s"`,
escapeQuotes(fieldname), escapeQuotes(filename)))
h.Set("Content-Type", "image/png")
part, err := writer.CreatePart(h)
// use part same as before
Definition of escapeQuotes
from multiple-part package.
var quoteEscaper = strings.NewReplacer("\\", "\\\\", `"`, "\\\"")
func escapeQuotes(s string) string {
return quoteEscaper.Replace(s)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论