如何在Node.js中当文件小于1KB时终止下载并尝试下一个URL
文件下载失败自动重试下一个URL的实现方案
需求说明
使用Node.js的https模块下载文件时,若目标URL不存在,模块不会抛出错误,只会生成一个1字节的run.jar文件。需要实现:下载完成后检测文件大小,若小于1KB则终止当前后续代码执行,自动尝试downloadurl数组中的下一个URL。
原始代码
const downloadurl = ['url1', 'url2'] const filename = 'run.jar' downloadurl.forEach((urls) => { https.get(urls, (httpsres) => { const path = `${installationdirectory}/${filename}` const filePath = fs.createWriteStream(path); httpsres.pipe(filePath); filePath.on('finish',() => { filePath.close(); const filesize = fs.statSync(path).size // 校验文件大小是否小于1KB if((filesize / 1024) < 1) return; // 希望文件小于1KB时跳过此日志,尝试下一个URL console.log('File downloaded!'); }) }) })
问题分析
原始代码用forEach遍历URL,会同时发起所有请求,无法实现“失败后再试下一个”的串行逻辑。必须改成串行处理,逐个尝试URL,直到下载成功(文件大小符合要求)为止。
解决方案
1. 封装下载校验函数
把下载和文件校验逻辑封装成返回Promise的异步函数,方便串行调用:
const https = require('https'); const fs = require('fs'); const path = require('path'); const downloadurl = ['url1', 'url2']; const filename = 'run.jar'; const installationdirectory = './downloads'; // 替换为你的实际路径 // 封装下载并校验的异步函数 async function downloadAndCheck(url) { return new Promise((resolve, reject) => { const filePath = path.join(installationdirectory, filename); // 发起请求 https.get(url, (res) => { // 提前判断响应状态码,避免下载无效内容 if (res.statusCode >= 400) { res.resume(); // 消耗响应体,避免内存泄漏 return resolve(false); } const writeStream = fs.createWriteStream(filePath); // 处理文件写入错误 writeStream.on('error', (err) => { console.error(`写入文件失败: ${err.message}`); writeStream.destroy(); resolve(false); }); // 下载完成后校验文件大小 writeStream.on('finish', () => { try { const stats = fs.statSync(filePath); const fileSizeKB = stats.size / 1024; // 大小>=1KB则认为下载成功 resolve(fileSizeKB >= 1); } catch (err) { console.error(`读取文件信息失败: ${err.message}`); resolve(false); } }); res.pipe(writeStream); }).on('error', (err) => { console.error(`请求URL失败: ${err.message}`); resolve(false); }); }); }
2. 串行遍历URL数组
用async/await循环遍历URL,逐个尝试,直到成功为止:
async function tryDownloads() { for (const url of downloadurl) { console.log(`尝试下载: ${url}`); const success = await downloadAndCheck(url); if (success) { console.log('文件下载成功!'); break; // 成功则终止循环,不再尝试后续URL } else { console.log(`下载失败,尝试下一个URL`); // 可选:删除无效的小文件,避免残留垃圾 try { fs.unlinkSync(path.join(installationdirectory, filename)); } catch (err) { console.error(`删除无效文件失败: ${err.message}`); } } } } // 启动下载流程 tryDownloads().catch((err) => { console.error(`下载流程出错: ${err.message}`); });
关键说明
- 串行处理:用
for...of配合await实现逐个请求,确保上一个请求处理完成后才尝试下一个。 - 提前校验状态码:在响应阶段先判断状态码,避免下载404等无效响应体。
- 全流程错误捕获:覆盖请求、文件写入、文件信息读取等环节的错误,确保流程不中断。
- 清理无效文件:下载失败后自动删除小文件,避免磁盘垃圾。
内容的提问来源于stack exchange,提问作者Martín Rubina
相关产品推荐
相关产品推荐

