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

如何从S3 Bucket获取可读流以通过Axios上传图片至外部API?

解决方案:Lambda从S3取文件上传至外部multipart/form-data API

核心问题

你之前的三种尝试都没有在FormData.append时正确指定文件名和文件Content-Type,导致外部API无法识别图片类型。本地用fs.createReadStream时,流会自动携带文件元数据,但S3的流/Buffer不会自动提供这些信息,必须显式声明。


正确实现方式

方式1:使用S3返回的Buffer(适合小文件)

先把S3文件下载到内存Buffer,再附加到FormData,同时指定文件名和Content-Type:

const AWS = require('aws-sdk');
const FormData = require('form-data');
const request = require('request-promise-native');

const s3 = new AWS.S3({ apiVersion: '2006-03-01' });

async function uploadToExternalAPI() {
  const requestParams = { key: 'your-image.png' };
  const bucketName = 'someBucketName';

  // 获取S3文件及元数据
  const s3Object = await s3.getObject({
    Key: requestParams.key,
    Bucket: bucketName
  }).promise();

  const formData = new FormData();
  // 关键:将Buffer附加到FormData时,指定文件名和Content-Type
  formData.append('photo', s3Object.Body, {
    filename: requestParams.key, // 用S3对象的Key作为文件名,确保有.png后缀
    contentType: s3Object.ContentType || 'image/png' // 优先用S3存储的Content-Type,兜底设为PNG
  });

  // 发起上传请求
  const uploadResult = await request({
    method: 'POST',
    url: upload_url,
    headers: formData.getHeaders(), // 用FormData自动生成的头,包含正确的multipart边界
    data: formData
  });

  return uploadResult;
}

方式2:使用S3可读流(适合大文件,避免内存占用过高)

如果文件较大,推荐用流直接传输,先通过headObject获取文件的Content-Type,再将流附加到FormData:

const AWS = require('aws-sdk');
const FormData = require('form-data');
const request = require('request-promise-native');

const s3 = new AWS.S3({ apiVersion: '2006-03-01' });

async function uploadToExternalAPIWithStream() {
  const requestParams = { key: 'your-image.png' };
  const bucketName = 'someBucketName';

  // 先获取文件的Content-Type(避免下载整个文件)
  const headInfo = await s3.headObject({
    Key: requestParams.key,
    Bucket: bucketName
  }).promise();
  const contentType = headInfo.ContentType || 'image/png';

  // 创建S3可读流
  const s3Stream = s3.getObject({
    Key: requestParams.key,
    Bucket: bucketName
  }).createReadStream();

  const formData = new FormData();
  // 附加流时指定文件名和Content-Type
  formData.append('photo', s3Stream, {
    filename: requestParams.key,
    contentType: contentType
  });

  // 发起上传请求
  const uploadResult = await request({
    method: 'POST',
    url: upload_url,
    headers: formData.getHeaders(),
    data: formData
  });

  return uploadResult;
}

原尝试的问题分析

  1. Option 1:你获取了S3对象的完整响应,但没有提取Body(实际文件Buffer),且未指定文件名和Content-Type,FormData无法生成正确的multipart字段,API无法识别文件类型。
  2. Option 2:使用了S3可读流,但未在append时声明文件名和Content-Type,FormData默认会将文件标记为application/octet-stream类型,不符合API对PNG的要求。
  3. Option 3:Promise逻辑错误——finish事件触发时,PassThrough流已经结束,返回的流没有数据;同时同样缺少文件名和Content-Type的声明。

内容的提问来源于stack exchange,提问作者Paramonov Vladimir

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 21:44:55