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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 23:45:43