You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Twitter API v2媒体上传失败:oauth-1.0a认证下Node.js报400错误

问题解决:Twitter API v2媒体上传返回400(media parameter is missing)

问题根源

你当前的代码把媒体文件转成Base64字符串后添加到FormData,但Twitter API v2的媒体上传接口要求media字段传递原始二进制文件内容,而非Base64编码后的字符串,这直接导致接口识别不到媒体参数,返回错误码38。

修复步骤

  1. 移除Base64编码步骤,直接将二进制Buffer作为文件添加到FormData
  2. 使用FormData的文件追加方式,指定文件名和媒体类型,确保接口能正确解析媒体内容
  3. 优化媒体获取逻辑,避免不必要的Blob转换(Node.js环境下可直接获取Buffer)

修正后的代码

媒体获取部分优化

// this comes from my db and is a s3 url of an image(png)
const mediaUrl = mediaItem.presigned_url;
const mediaName = mediaItem.name || mediaItem.s3_key;

// Fetch media data - Node.js环境下直接获取Buffer,无需转Blob
const mediaResponse = await fetch(mediaUrl);
if (!mediaResponse.ok) {
  console.error(
    "Failed to fetch media:",
    mediaResponse.status,
    await mediaResponse.text()
  );
  throw new Error(`Failed to fetch media: ${mediaResponse.status}`);
}

// 直接获取Buffer,跳过Blob转换
const buffer = await mediaResponse.buffer();

// Handle media based on type
if (
  mediaItem.media_type.startsWith("image/") ||
  mediaItem.media_type === "image"
) {
  // For images, upload directly
  const mediaId = await uploadMediaDirect(
    buffer,
    mediaItem.media_type,
    oauth,
    token,
    mediaName // 传递文件名
  );
}

媒体上传函数修正

async function uploadMediaDirect(mediaBuffer, mediaType, oauth, token, filename) {
  try {
    const requestData = {
      url: "https://api.twitter.com/2/media/upload",
      method: "POST",
    };

    const headers = oauth.toHeader(oauth.authorize(requestData, token));

    const formData = new FormData();
    // 直接传递Buffer作为文件,指定文件名和媒体类型
    formData.append("media", mediaBuffer, {
      filename: filename || "image.png",
      contentType: mediaType
    });

    const response = await fetch(requestData.url, {
      method: "POST",
      headers: headers,
      body: formData,
    });

    if (!response.ok) {
      const errorText = await response.text();
      console.error("Media upload failed:", response.status, errorText);
      throw new Error(`Media upload failed: ${response.status}`);
    }

    const responseData = await response.json();
    return responseData.media_id_string;
  } catch (error) {
    console.error("Error uploading media:", error);
    throw new Error(`Media upload failed: ${error.message}`);
  }
}

额外注意点

  • Node.js环境下使用node-fetch时,response.buffer()是原生支持的,无需转换为Blob
  • 不要手动设置Content-Type为multipart/form-data,fetch会自动根据FormData生成正确的头部(包括boundary)
  • 确保你的OAuth签名逻辑正确,因为媒体上传接口同样需要符合OAuth 1.0a的签名要求(你已能发布普通推文,这部分应该没问题)

内容的提问来源于stack exchange,提问作者Devansh Sahni

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 13:40:20