0

我正在关注这个官方文档:https ://developers.facebook.com/docs/messenger-platform/reference/attachment-upload-api/尝试发送带有视频附件的消息。我试过的:

//...
    api.BaseRoutes.Conversation.Handle("/video", api.ApiSessionRequired(sendVideo)).Methods("POST")

//...

func sendVideo(c *Context, w http.ResponseWriter, r *http.Request) {
    c.RequirePageId().RequireConversationId()
    if c.Err != nil {
        return
    }

    conversation, getErr := c.App.GetConversation(c.Params.ConversationId)
    if getErr != nil {
        c.Err = getErr
        return
    }

    if err := r.ParseMultipartForm(25*1024*1024); err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }

    // detect file header
    f, _, err := r.FormFile("files")

    // Create a buffer to store the header of the file in
    fileHeader := make([]byte, 512)

    // Copy the headers into the FileHeader buffer
    if _, err := f.Read(fileHeader); err != nil {

    }

    // set position back to start.
    if _, err := f.Seek(0, 0); err != nil {

    }

    _fileType := http.DetectContentType(fileHeader)

    m := r.MultipartForm

    fileArray, ok := m.File["files"]
    if !ok {
        c.Err = model.NewAppError("uploadPlugin", "api.plugin.upload.no_file.app_error", nil, "", http.StatusBadRequest)
        return
    }

    if len(fileArray) <= 0 {
        c.Err = model.NewAppError("uploadPlugin", "api.plugin.upload.array.app_error", nil, "", http.StatusBadRequest)
        return
    }

    file, err := fileArray[0].Open()

    if err != nil {
        c.Err = model.NewAppError("uploadPlugin", "api.plugin.upload.file.app_error", nil, "", http.StatusBadRequest)
        return
    }
    defer file.Close()

    // build a form body
    body := &bytes.Buffer{}
    writer := multipart.NewWriter(body)

    // add form fields
    writer.WriteField("message", "{\"attachment\":{\"type\":\"video\", \"payload\":{\"is_reusable\":true}}}\")

    //fileWriter, err := CreateFormFile(writer, "filedata", fileArray[0].Filename)

    // add a form file to the body
    fileWriter, err := writer.CreateFormFile("filedata", fileArray[0].Filename)
    if err != nil {
        c.Err = model.NewAppError("upload_video", "upload_video.error", nil, "", http.StatusBadRequest)
        return
    }

    // copy the file into the fileWriter
    _, err = io.Copy(fileWriter, file)
    if err != nil {
        c.Err = model.NewAppError("upload_video", "upload_video.error", nil, "", http.StatusBadRequest)
        return
    }

    // Close the body writer
    writer.Close()

    reqUrl := "https://graph.facebook.com/v10.0/me/message_attachments"
    token := c.App.Session().GetPageToken(c.Params.PageId)
    reqUrl += "?access_token=" + token

    var netTransport = &http.Transport{
        Dial: (&net.Dialer{
            Timeout: 120 * time.Second,
        }).Dial,
        TLSHandshakeTimeout:   120 * time.Second,
        ResponseHeaderTimeout: 120 * time.Second, // This will fixed the i/o timeout error
    }

    client := &http.Client{
        Timeout:   time.Second * 120,
        Transport: netTransport,
    }

    req, _ := http.NewRequest("POST", reqUrl, body)

    req.Header.Set("Authorization", "Bearer "+token)
    req.Header.Set("Content-Type", writer.FormDataContentType())

    resp, err1 := client.Do(req)

    if err1 != nil {
        c.Err = model.NewAppError("send_video", err1.Error(), nil, "", http.StatusBadRequest)
        return
    } else {
        defer resp.Body.Close()
        var bodyBytes []byte
        bodyBytes, _ = ioutil.ReadAll(resp.Body)
        resp.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))

        if resp.StatusCode != http.StatusOK {
            fbErr := facebookgraph.FacebookErrorFromJson(resp.Body)
            fmt.Println("__ERROR___", fbErr)
            c.Err = model.NewAppErrorFromFacebookError("send_video", fbErr)
            return
        }

        // Do what ever we want with attachment_id result
    }

    ReturnStatusOK(w)
}

但总是因来自 Facebook 的错误而失败:

{
  "error": {
    "message": "(#100) Upload attachment failure.",
    "type": "OAuthException",
    "code": 100,
    "error_subcode": 2018047,
    "fbtrace_id": "A2hkvhTQlmA98XmcrPvSy8O"
  }
}

根据 Facebook 文档,错误子代码为:2018047:

上传附件失败。触发此错误的常见方法是提供的媒体类型与 URL 中提供的文件类型不匹配

我也尝试通过 cURL 并且一切正常:

curl \
-F 'message={"attachment":{"type":"video", "payload":{"is_reusable":true}}}' \
-F 'filedata=@/home/cong/Downloads/123.mp4;type=video/mp4' \
"https://graph.facebook.com/v10.0/me/message_attachments?access_token=EAAUxUcj3C64BADxxsm70hZCXTMO0eQHmSp..."
{"attachment_id":"382840319882695"}% 

如果我将“视频”更改为“文件”,则上传成功:

writer.WriteField("message", "{\"attachment\":{\"type\":\"file\", \"payload\":{\"is_reusable\":true}}}\")

但是Facebook会将视频作为“文件附件”发送(不能作为视频查看,必须下载才能查看)。那不是我想要的。

谁能告诉我如何解决这个问题?非常感谢!

4

1 回答 1

0

你不应该这样写

fileWriter, err := writer.CreateFormFile("filedata", fileArray[0].Filename)

因为它将使用标题 "Content-Type": "application/octet-stream" 创建,并且 facebook 将发送错误文件类型。像这样替换这一行:

    h := make(textproto.MIMEHeader)
    h.Set("Content-Disposition", fmt.Sprintf(`form-data; name="%s"; filename="%s"`,"filedata", fileArray[0].Filename)))
    h.Set("Content-Type", "video/mp4")

    fileWriter, err := writer.CreatePart(h)

使用 CreatePart(header) 并重试

于 2021-12-21T05:09:09.443 回答