使用NodeJS res.download无法下载大体积Zip文件问题
问题分析与解决方案
1. 变量名大小写错误(直接导致文件损坏)
代码中定义的是const outFile = '/tmp/...',但后续调用zip.writeZip(outfile)和res.download(outfile)时用的是小写outfile,这会导致写入的文件路径错误(实际创建的是当前目录下的outfile文件,而非/tmp下的目标文件),最终下载的是不存在或空的无效Zip文件。
修复: 统一变量名,全部改为outFile:
zip.writeZip(outFile); res.download(outFile, function(err) { if(err) { logger.error("Download failed: " + err); res.status(500).send("Download failed"); } });
2. 大文件同步处理导致内存溢出
AdmZip的同步压缩方式会将整个文件夹内容加载到内存中,处理大体积文件夹时极易触发内存溢出,导致Zip文件写入不完整、损坏。
替代方案:使用流式压缩库archiverarchiver支持流式压缩,无需将全部内容加载到内存,更适合大文件场景:
const archiver = require('archiver'); const fs = require('fs'); // 初始化输出流 const output = fs.createWriteStream(outFile); const archive = archiver('zip', { zlib: { level: 9 } }); output.on('close', function() { // 压缩完成后触发下载 res.download(outFile, function(err) { if(err) { logger.error("Download failed: " + err); res.status(500).send("Download failed"); } // 下载完成后清理临时文件 fs.unlinkSync(outFile); }); }); archive.on('error', function(err) { logger.error("Zip compression failed: " + err); res.status(500).send("Compression failed"); fs.unlinkSync(outFile); }); // 管道连接输出流 archive.pipe(output); // 添加文件夹到压缩包 archive.directory(path, false); // 完成压缩 archive.finalize();
3. 错误处理不完整
- 原代码中
res.download的错误仅打印日志,未向客户端返回错误响应,导致浏览器无法正确感知失败原因。 - 临时文件未在失败时清理,可能导致
/tmp目录残留无效文件。
修复: 在错误分支中添加响应状态码,并清理临时文件:
// 示例:在catch块中补充 catch (e) { logger.error("Zip file failed with exception " + e); // 清理无效临时文件 if(fs.existsSync(outFile)) { fs.unlinkSync(outFile); } res.status(500).send("Compression failed"); }
4. 同步文件操作的性能问题
原代码中fs.existsSync和fs.unlinkSync是同步操作,在高并发场景下会阻塞事件循环,建议改用异步版本:
fs.access(outFile, fs.constants.F_OK, (err) => { if (!err) { fs.unlink(outFile, (unlinkErr) => { if(unlinkErr) logger.error("Failed to delete old zip: " + unlinkErr); // 执行压缩逻辑 }); } else { // 执行压缩逻辑 } });
内容的提问来源于stack exchange,提问作者VultureMF
相关产品推荐
相关产品推荐

