Node.js客户端向服务器传大文件如何避免内存溢出错误?
大文件上传内存溢出问题解决办法
你的代码出现内存溢出和页面冻结的核心原因,是把整个大文件一次性加载到内存中处理:
FileReader.readAsArrayBuffer会将20MB+的文件完整读入内存,生成ArrayBuffer- 转成
Uint8Array后又用Array.from()转成普通数组,这一步会额外复制一份数据,内存占用直接翻倍 - 最后
JSON.stringify处理超大数组,不仅耗时极长,还会进一步占用大量内存
下面给出两种解决方案:
方案一:用FormData直接上传(最简单高效)
不需要手动读取文件内容,浏览器会自动以流式方式上传文件,不会把整个文件塞进内存。
for (let i = 0; i < files.length; i++) { const file = files[i]; const formData = new FormData(); formData.append('file', file); // 如需额外传递文件名、类型,可添加以下字段(可选,file对象本身已包含这些信息) // formData.append('fileName', file.name); // formData.append('fileType', file.type); fetch("/file", { method: "POST", body: formData // 无需手动设置Content-Type,浏览器会自动添加multipart/form-data头 }); }
注意:服务器端需要调整为接收multipart/form-data格式的文件,主流后端框架都有现成的处理工具。
方案二:分片上传(适合超大文件/断点续传需求)
如果需要支持GB级超大文件或断点续传,可以把文件切割成小分片逐个上传:
async function uploadFile(file) { const chunkSize = 1024 * 1024; // 每片1MB,可根据需求调整 const totalChunks = Math.ceil(file.size / chunkSize); const fileName = file.name; for (let chunkIndex = 0; chunkIndex < totalChunks; chunkIndex++) { const start = chunkIndex * chunkSize; const end = Math.min(start + chunkSize, file.size); const chunk = file.slice(start, end); // 切割文件分片 const formData = new FormData(); formData.append('chunk', chunk); formData.append('chunkIndex', chunkIndex); formData.append('totalChunks', totalChunks); formData.append('fileName', fileName); // 等待当前分片上传完成再传下一个,避免并发请求过多 await fetch("/file-chunk", { method: "POST", body: formData }); } // 所有分片上传完成后,通知服务器合并文件 await fetch("/merge-file", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ fileName, totalChunks }) }); } // 批量上传文件 for (let i = 0; i < files.length; i++) { uploadFile(files[i]); }
服务器端需要配合实现:
- 接收每个分片,保存到临时存储目录,文件名包含分片索引和原文件名
- 收到合并请求后,按分片索引顺序拼接所有分片,生成完整文件
- 可选:支持断点续传,先查询已上传的分片,跳过重复上传
内容的提问来源于stack exchange,提问作者Aayush
相关产品推荐
相关产品推荐

