上传附件失败 Facebook 附件上传 API

问题描述 投票:0回答:2

我正在尝试通过 Facebook 附件上传 API 将附件添加到我的消息中。

我正在从一个页面(我是其管理员)发送消息给已向我的页面发送消息的用户。 发送简单的短信,并且附件作为类型“文件”也可以正常工作。但是当我将 'image''audio' 作为附件放入时,Facebook 会发送响应:

错误:{ message: '(#100) 上传附件失败。', 类型:'OAuthException', 代码:100, 错误子代码:2018047, fbtrace_id: 'AzfHWxf3AnikXiCCC-hYJOu' }

这是我的代码:

let messageData = {
          message: {
            attachment: {
              **type: "image"**,
              payload: {
                is_reusable: true,
                url: <url of the image>
              }
            }
          }
        }
        
let data = await axios.post(`https://graph.facebook.com/v8.0/me/message_attachments?access_token=${accessToken}`, messageData)
facebook-graph-api facebook-javascript-sdk
2个回答
0
投票

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

来自官方文档


0
投票

对于 Golang,这是我的复制粘贴示例,请参阅评论。

func UploadAttachment(dataBytes []byte, fileName string, contentType string) (string, error) {

    // Create a io.Reader to hold dataBytes and pass to http
    reader := bytes.NewReader(dataBytes)

    // Create a buffer and multipart writer
    var b bytes.Buffer
    multipartWriter := multipart.NewWriter(&b)

    // Define the structs
    type Payload struct {
        Reusable bool `json:"is_reusable"`
    }

    type Attachment struct {
        Type    string  `json:"type"`
        Payload Payload `json:"payload"`
    }

    type Message struct {
        Attachment Attachment `json:"attachment"`
    }
    msg := Message{
        Attachment: Attachment{
            Type: getTypeFromContentType(contentType),
            Payload: Payload{
                Reusable: true,
            },
        },
    }
    // Marshal the struct to JSON
    jsonData, err := json.Marshal(msg)
    if err != nil {
        fmt.Println("Error marshalling to JSON:", err)
        return "", err
    }

    // Convert JSON bytes to string
    jsonString := string(jsonData)

    // Debug
    fmt.Println("Sending :" + jsonString)

    multipartWriter.WriteField("message", jsonString)
    multipartWriter.WriteField("access_token", os.Getenv("FACEBOOK_FAN_PERMANENT_TOKEN"))

    // Note ! formFileWriter is different from formFieldWriter, don't be lazy and reuse variable like (fw) will cause confusion from many "sample code"
    // Note ! w.CreateFormFile by default DO h.Set("Content-Type", "application/octet-stream"), but facebook requires the content-type matching or you get an error_subcode: 2018047
    // If you're using w.CreateFormFile and specify type="file" in the json payload, it's fine with facebook (no extra check). But when you specify type="image" in the json payload, here's why error_subcode: 2018047 kicks in.
    // Therefore, i copied from w.CreateFormFile (which is just a wrapper of CreatePart) and set the Content-Type to the correct one.
    // Manually create the form file part, setting the Content-Type explicitly
    // This concept also apply to whatsapp upload media

    h := make(textproto.MIMEHeader)
    h.Set("Content-Disposition", fmt.Sprintf(`form-data; name="file"; filename="%s"`, fileName))
    h.Set("Content-Type", contentType) // << here
    formFileWriter, err := multipartWriter.CreatePart(h)
    if err != nil {
        return "", err
    }

    // Write the binary data from reader to formFileWriter
    if _, err := io.Copy(formFileWriter, reader); err != nil {
        return "", err
    }

    // Close the writer
    multipartWriter.Close()

    // Create and send the request
    // I don't like to put access_token in the url (safer)
    url := os.Getenv("FACEBOOK_FAN_ENDPOINT") + "/message_attachments"

    // Debug
    fmt.Println("Posting to url " + url)

    req, err := http.NewRequest("POST", url, &b)
    if err != nil {
        return "", err
    }
    req.Header.Set("Content-Type", multipartWriter.FormDataContentType()) // << multipart/form-data

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        return "", err
    }
    defer resp.Body.Close()

    // Read the response body
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return "", fmt.Errorf("error reading response body: %w", err)
    }

    // Debug Print the response body
    fmt.Println("Response Body:", string(body))

    // Check the response
    if resp.StatusCode != http.StatusOK {
        return "", fmt.Errorf("http not OK")
    }

    // Parse the JSON response
    var attachmentResp struct {
        ID string `json:"attachment_id"`
    }
    if err := json.Unmarshal(body, &attachmentResp); err != nil {
        return "", err
    }

    // Assuming the response contains attachment_id
    if attachmentResp.ID != "" {
        return attachmentResp.ID, nil
    }

    return "", fmt.Errorf("no attachment ID found in response")

}

// Depends on contenType select typeField for the message payload
func getTypeFromContentType(contentType string) string { 
    var typeField = "file" // default as file
    switch contentType {
    case "image/jpeg":
        fallthrough
    case "image/png":
        typeField = "image"
    case "video/mp4":
        typeField = "video"
    case "text/plain":
        fallthrough
    case "application/pdf":
        fallthrough
    case "application/vnd.ms-powerpoint":
        fallthrough
    case "application/msword":
        fallthrough
    case "application/vnd.ms-excel":
        fallthrough
    case "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
        fallthrough
    case "application/vnd.openxmlformats-officedocument.presentationml.presentation":
        fallthrough
    case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":
        typeField = "file"
    }
    return typeField
}
© www.soinside.com 2019 - 2024. All rights reserved.