使用Node.js AWS SDK v3上传流到Amazon S3出现Transfer-Encoding报错如何解决
问题成因
- S3原生
PutObject接口不支持Transfer-Encoding: chunked传输方式:当你传入未知长度的可读流(比如Archiver生成的Transform流)作为Body时,AWS SDK无法提前获取流的总大小,会自动添加Transfer-Encoding: chunked请求头,而S3的PutObject接口不支持该请求头,直接触发NotImplemented报错。 - 代码存在异步时序问题:
client.send是异步操作,你在调用send之后才向archive流添加文件、执行finalize,send执行时流还没有实际数据,也会触发空请求相关的报错。
解决方案
推荐使用AWS SDK v3官方提供的@aws-sdk/lib-storage包中的Upload工具,它底层自动使用S3分片上传接口适配未知长度的流式传输,无需提前计算文件大小,也不会触发chunked请求头问题。
首先安装对应依赖:
npm install @aws-sdk/lib-storage
修改后的可运行代码如下:
import fs from 'fs' import { S3Client } from '@aws-sdk/client-s3' import { Upload } from '@aws-sdk/lib-storage' import archiver from 'archiver' async function run() { const archive = archiver('zip') const client = new S3Client({ region: process.env.AWS_REGION }) try { // 初始化上传任务,传入archive流 const upload = new Upload({ client, params: { Bucket: process.env.AWS_DEFAULT_BUCKET, Key: 'testupload.zip', ContentType: 'application/zip', Body: archive, } }) // 可选:监听上传进度 upload.on('httpUploadProgress', (progress) => { console.log(`上传进度: ${progress.loaded}/${progress.total || '未知'}`) }) // 等待上传完成 const response = await upload.done() console.log('上传成功', response) } catch (err) { console.error('上传压缩包到S3失败') console.error(err) // 按需处理错误返回 // res.status(501).json({ message: '配置S3上传失败' }) } // 往压缩包添加文件后执行finalize archive.file('/fixtures/harambe.jpg', { name: 'harambe.jpg' }) archive.finalize() } run()
如果你的压缩包体积很小,也可以将流全部读取为Buffer后再调用PutObject,避免使用分片上传:
// 流转Buffer工具函数 const streamToBuffer = async (stream) => { const chunks = [] for await (const chunk of stream) { chunks.push(chunk) } return Buffer.concat(chunks) } // 调用示例 archive.file('/fixtures/harambe.jpg', { name: 'harambe.jpg' }) archive.finalize() const buffer = await streamToBuffer(archive) // 将buffer作为Body传给PutObjectCommand即可
内容的提问来源于stack exchange,提问作者Josh Kopecek
相关产品推荐
相关产品推荐

