使用node-fetch时持续触发socket hang up错误的解决求助
解决批量fetch请求导致的socket hang up问题
你的判断完全正确——socket hang up错误就是因为一次性发起了太多并发请求,要么耗尽了本地socket连接资源,要么触发了目标服务器的限流策略。咱们从三个核心方向来修复这个问题:
1. 优化fetch请求:只拿响应头,不用下载整张图
你只需要校验Content-Type,完全没必要下载图片内容。改用HEAD请求,能大幅减少带宽占用和请求耗时:
const getImage = async (url) => { try { // 使用HEAD请求,仅获取响应头信息 const res = await fetch(encodeURI(url), { method: 'HEAD' }); const contentType = res.headers.get("content-type"); console.log(`URL: ${url} | Content-Type: ${contentType}`); return contentType?.includes('image') ? true : false; } catch (err) { console.error(`请求失败: ${url}`, err.message); throw err; // 抛出错误方便后续重试逻辑处理 } };
2. 加重试机制:应对临时网络/服务器波动
对于临时的连接失败,重试几次通常能解决问题。给请求逻辑套一层重试逻辑:
const getImageWithRetry = async (url, maxRetries = 3, baseDelay = 1000) => { let attempt = 0; while (attempt < maxRetries) { try { return await getImage(url); } catch (err) { attempt++; console.warn(`重试第${attempt}次: ${url}`); // 重试间隔逐渐拉长,避免频繁重试触发更严格的限流 await new Promise(resolve => setTimeout(resolve, baseDelay * attempt)); } } console.error(`多次重试仍失败: ${url}`); return false; };
3. 控制并发数:避免瞬间发起大量请求
直接循环调用getImage会瞬间创建几十上百个并发连接,咱们需要限制同时进行的请求数量。这里写一个简单的批量处理函数:
// 批量处理URL,控制同时发起的请求数 const batchProcessUrls = async (urls, concurrency = 5) => { const results = []; // 分批次处理,每批次最多concurrency个请求 for (let i = 0; i < urls.length; i += concurrency) { const batch = urls.slice(i, i + concurrency); // 等待当前批次所有请求完成,再进行下一批 const batchResults = await Promise.all( batch.map(url => getImageWithRetry(url)) ); results.push(...batchResults); // 批次之间加个小延迟,进一步降低请求频率 await new Promise(resolve => setTimeout(resolve, 500)); } return results; };
4. 修改数据库循环的调用方式
原来的同步循环会一次性发起所有请求,现在改成异步批量处理:
connection.query(sql, async (error, results, fields) => { if (error) { return console.error(error.message); } // 提取所有图片URL const imageUrls = results.map(item => item.image_url); // 批量处理,并发数设为5(可根据实际情况调整) const checkResults = await batchProcessUrls(imageUrls, 5); // 这里可以根据校验结果做后续操作,比如更新数据库状态 console.log('所有URL校验完成'); connection.end(); // 处理完所有请求再关闭数据库连接 });
额外小贴士
- 调整
concurrency值:根据目标服务器的宽容度和本地网络情况调整,建议从5-10开始测试,逐步找到合适的数值。 - 不要无限重试:设置合理的
maxRetries(比如3次),避免死循环。 - 异常兜底:确保所有异步操作都有错误捕获,避免出现未处理的Promise异常。
内容的提问来源于stack exchange,提问作者Ollie2619
相关产品推荐
相关产品推荐

