如何从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; }
原尝试的问题分析
- Option 1:你获取了S3对象的完整响应,但没有提取
Body(实际文件Buffer),且未指定文件名和Content-Type,FormData无法生成正确的multipart字段,API无法识别文件类型。 - Option 2:使用了S3可读流,但未在
append时声明文件名和Content-Type,FormData默认会将文件标记为application/octet-stream类型,不符合API对PNG的要求。 - Option 3:Promise逻辑错误——
finish事件触发时,PassThrough流已经结束,返回的流没有数据;同时同样缺少文件名和Content-Type的声明。
内容的提问来源于stack exchange,提问作者Paramonov Vladimir
相关产品推荐
相关产品推荐

