Node.js下载Census.gov 6GB大文件频繁中断的解决方法咨询
解决Node.js大文件下载中途中断问题
问题根源
你的代码缺少错误处理逻辑、未处理流的背压问题,且默认HTTP超时设置不足以支撑6GB大文件的长时间下载,这些都是导致下载中途中断的核心原因。
具体修复方案
1. 监听所有错误事件
HTTP请求流、文件写入流都可能因网络波动、磁盘异常等抛出错误,必须监听这些错误才能避免静默失败,并快速定位问题。
2. 处理流的背压
当file.write(chunk)返回false时,说明文件流暂时无法处理更多数据,此时需暂停HTTP响应流,等待文件流的drain事件触发后再恢复传输,否则会导致数据丢失或下载中断。
3. 调整HTTP请求超时
默认HTTP请求超时(通常2分钟)远不足以支撑大文件下载,需手动设置更长的超时时间,或直接禁用超时。
4. 实现断点续传(推荐)
若服务器支持Range请求,可记录已下载的文件大小,下次启动时从断点处继续下载,避免因网络中断重新下载整个文件。
修复后的完整代码
const fs = require('fs'); const http = require('http'); // 若目标地址是HTTPS,替换为https模块 const fileName = 'target-large-file.zip'; const url = 'http://census.gov/path/to/your/6gb-file.zip'; // 检查已下载文件大小,用于断点续传 let downloadedSize = 0; if (fs.existsSync(fileName)) { const stats = fs.statSync(fileName); downloadedSize = stats.size; } const requestOptions = { headers: { // 支持断点续传时,添加Range请求头 ...(downloadedSize > 0 ? { Range: `bytes=${downloadedSize}-` } : {}) }, timeout: 0 // 禁用超时,或设置足够大的值,比如3600000(1小时) }; // 写入文件:续传用追加模式,全新下载用覆盖模式 const fileStream = fs.createWriteStream(fileName, { flags: downloadedSize > 0 ? 'a' : 'w' }); const httpRequest = http.get(url, requestOptions, (res) => { let totalFileSize = downloadedSize; // 处理续传响应(206 Partial Content) if (res.statusCode === 206) { const contentRange = res.headers['content-range']; totalFileSize = parseInt(contentRange.split('/')[1], 10); } else if (res.statusCode === 200) { totalFileSize = parseInt(res.headers['content-length'], 10); } let currentDownloaded = downloadedSize; res .on('data', (chunk) => { // 处理流背压 const canWrite = fileStream.write(chunk); if (!canWrite) { res.pause(); } currentDownloaded += chunk.length; process.stdout.write(`已下载 ${(currentDownloaded / 1000000).toFixed(2)} MB / 总计 ${(totalFileSize / 1000000).toFixed(2)} MB\r`); }) .on('end', async () => { fileStream.end(); console.log(`${fileName} 下载完成。`); // 下载完成后执行你的zip处理逻辑 // await processZipFile(fileName); }) .on('error', (err) => { console.error('HTTP响应流错误:', err); fileStream.close(); }); // 文件流可继续写入时,恢复HTTP流传输 fileStream.on('drain', () => { res.resume(); }); // 文件写入错误处理 fileStream.on('error', (err) => { console.error('文件写入错误:', err); httpRequest.abort(); }); }); // 请求超时处理 httpRequest.on('timeout', () => { console.error('请求超时'); httpRequest.abort(); }); // 请求发起阶段错误处理 httpRequest.on('error', (err) => { console.error('HTTP请求错误:', err); fileStream.close(); });
额外注意事项
- 确保磁盘有足够空间存储6GB文件。
- 若目标地址是HTTPS,需将代码中的
http模块替换为https模块。 - 可添加重试逻辑,当下载失败时自动触发断点续传重试。
内容的提问来源于stack exchange,提问作者Sam
相关产品推荐
相关产品推荐

