使用AWS SDK v3流式上传文件到S3报MissingContentLength错误排查
解决@aws-sdk/client-s3 v3流式上传DigitalOcean Spaces时的MissingContentLength错误(411)
问题原因
DigitalOcean Spaces虽兼容S3 API,但对无ContentLength的普通PUT请求支持有限。当你用fs.createReadStream流式上传且无法获取文件长度时,直接调用PutObjectCommand会因请求未携带ContentLength头部,被服务器以411(要求内容长度)拒绝。此外,@aws-sdk/client-s3 v3默认仅对大于100MB的文件自动触发分块上传,你的50MB文件未达阈值,因此不会自动启用分块模式绕过ContentLength校验。
解决办法
方法1:使用TransferManager自动分块上传(推荐,适配大文件扩容)
借助@aws-sdk/lib-storage中的Upload类,它会自动将文件拆分为小块上传,无需提前获取ContentLength,同时支持断点续传,非常适合后续扩容的大文件场景。
- 先安装依赖:
npm install @aws-sdk/client-s3 @aws-sdk/lib-storage
- 实现代码:
const { S3Client } = require("@aws-sdk/client-s3"); const { Upload } = require("@aws-sdk/lib-storage"); const fs = require("fs"); // 初始化S3客户端(替换为你的Spaces配置) const s3Client = new S3Client({ region: "nyc3", endpoint: "https://nyc3.digitaloceanspaces.com", credentials: { accessKeyId: "你的AccessKey", secretAccessKey: "你的SecretKey" } }); const uploadStream = async () => { const fileStream = fs.createReadStream("/本地文件路径"); const uploadParams = { Bucket: "你的Spaces桶名", Key: "目标文件名", Body: fileStream }; try { const upload = new Upload({ client: s3Client, params: uploadParams }); // 可选:监听上传进度 upload.on("httpUploadProgress", (progress) => { console.log(`上传进度: ${Math.round((progress.loaded / progress.total) * 100)}%`); }); const result = await upload.done(); console.log("上传完成", result); } catch (err) { console.error("上传失败", err); } }; uploadStream();
方法2:手动启用Chunked编码
如果不想用分块上传,可通过配置客户端的HTTP处理器,强制开启Transfer-Encoding: chunked,让请求无需携带ContentLength即可被服务器接受。
- 安装依赖(若已安装客户端则无需重复):
npm install @aws-sdk/client-s3 @aws-sdk/node-http-handler
- 实现代码:
const { S3Client, PutObjectCommand } = require("@aws-sdk/client-s3"); const { NodeHttpHandler } = require("@aws-sdk/node-http-handler"); const fs = require("fs"); // 初始化带Chunked编码的S3客户端 const s3Client = new S3Client({ region: "nyc3", endpoint: "https://nyc3.digitaloceanspaces.com", credentials: { accessKeyId: "你的AccessKey", secretAccessKey: "你的SecretKey" }, requestHandler: new NodeHttpHandler({ enableChunkedEncoding: true, // 强制开启Chunked编码 requestTimeout: 0, // 大文件上传需禁用超时限制 socketTimeout: 0 }) }); const uploadStream = async () => { const fileStream = fs.createReadStream("/本地文件路径"); const command = new PutObjectCommand({ Bucket: "你的Spaces桶名", Key: "目标文件名", Body: fileStream }); try { const result = await s3Client.send(command); console.log("上传完成", result); } catch (err) { console.error("上传失败", err); } }; uploadStream();
注意:部分DigitalOcean Spaces区域可能对Chunked编码支持有限,若此方法无效,优先使用方法1。
内容的提问来源于stack exchange,提问作者Nullndr
相关产品推荐
相关产品推荐

