Node.js向AWS S3上传2GB大文件报RangeError求助
解决AWS S3大文件(2-5GB)简单上传问题
问题根源
直接使用file.buffer通过PutObjectCommand上传大文件时,整个文件会被加载到内存中,触发Node.js哈希计算的内存限制,导致RangeError: data is too long报错。S3的PutObject本身支持最大5GB文件上传,无需分片,只需调整上传方式避免内存溢出。
方案1:服务端用可读流替代Buffer上传
改用可读流分块处理文件,避免将整个文件加载到内存,同时绕过哈希计算的内存限制。
代码示例
如果文件存储在磁盘(推荐用multer.diskStorage替代memoryStorage接收文件):
const { PutObjectCommand, S3Client } = require("@aws-sdk/client-s3"); const fs = require("fs"); const s3 = new S3Client({ region: "你的区域", credentials: { /* 你的认证信息 */ } }); async function uploadFileToS3(file) { const command = new PutObjectCommand({ Bucket: "你的存储桶名称", Key: `videos/${Date.now()}-${file.originalname}`, Body: fs.createReadStream(file.path), // 用磁盘文件流替代buffer ContentType: file.mimetype }); try { const result = await s3.send(command); console.log("上传完成", result); return result; } catch (err) { console.error("上传失败", err); throw err; } }
如果必须使用内存中的Buffer,可将Buffer转为可读流(仍建议优先用磁盘流):
const { Readable } = require("stream"); // ... Body: Readable.from(file.buffer),
方案2:使用预签名URL上传(推荐,服务端无内存压力)
预签名URL生成后,需通过HTTP PUT请求将文件数据发送到该URL,服务端无需处理文件内容,完全由客户端/HTTP工具完成上传。
步骤1:服务端生成预签名URL
const { PutObjectCommand, S3Client } = require("@aws-sdk/client-s3"); const { getSignedUrl } = require("@aws-sdk/s3-request-presigner"); const s3 = new S3Client({ /* 你的配置 */ }); async function getUploadUrl(bucket, key, contentType) { const command = new PutObjectCommand({ Bucket: bucket, Key: key, ContentType: contentType }); return await getSignedUrl(s3, command, { expiresIn: 3600 }); }
步骤2:发起PUT请求上传文件
服务端侧上传(接收文件后转传)
const fetch = require("node-fetch"); const fs = require("fs"); async function uploadViaSignedUrl(signedUrl, file) { const stream = fs.createReadStream(file.path); const response = await fetch(signedUrl, { method: "PUT", body: stream, headers: { "Content-Type": file.mimetype } }); if (!response.ok) { throw new Error(`上传失败:${await response.text()}`); } console.log("上传成功"); }
前端侧上传(直接由用户浏览器上传)
// 前端JS示例 async function uploadFile(signedUrl, file) { const response = await fetch(signedUrl, { method: "PUT", body: file, headers: { "Content-Type": file.type } }); if (response.ok) { alert("上传完成"); } else { alert(`上传失败:${await response.text()}`); } }
说明
S3的PutObject接口原生支持最大5GB文件上传,完全覆盖你4~5GB以下的需求,无需实现分片上传逻辑。两种方案中,预签名URL上传更适合大文件场景,服务端无需承担内存压力,同时可将上传流量分散到客户端。
内容的提问来源于stack exchange,提问作者MichalZard
相关产品推荐
相关产品推荐

