You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js使用axios并行执行上千个请求出现连接报错如何解决?

报错原因

你当前的代码会一次性并发发起1417个HTTP请求,远超客户端系统的最大socket限制,同时也会触发目标站点的限流策略,因此会出现连接超时、连接重置、socket挂断这类错误。

解决方案

1. 限制请求并发数

不要直接把所有请求丢给Promise.all执行,控制同一时间发起的请求数量,建议设置为5-20之间(可根据目标站点的耐受度调整)。

原生JS分批实现(无需第三方库)

// 自定义分批执行函数,concurrency为并发数
async function batchRun(tasks, concurrency = 10) {
  const result = []
  for (let i = 0; i < tasks.length; i += concurrency) {
    const batchTasks = tasks.slice(i, i + concurrency).map(task => scrapeContent(task))
    const batchRes = await Promise.all(batchTasks)
    result.push(...batchRes)
  }
  return result
}

// 修改执行函数
async function scraper(links) {
  try {
    const newsContent = await batchRun(links, 8) // 一次并发跑8个请求
    console.log(newsContent)
  } catch (error) {
    console.log({ in: "scraper", message: error.message })
  }
}

用p-limit库实现(更灵活)

先执行安装命令:npm i p-limit

const pLimit = require('p-limit')
const limit = pLimit(8) // 并发数设为8

async function scraper(links) {
  try {
    const promises = links.map(item => limit(() => scrapeContent(item)))
    const newsContent = await Promise.all(promises)
    console.log(newsContent)
  } catch (error) {
    console.log({ in: "scraper", message: error.message })
  }
}

2. 优化axios配置

提前创建复用的axios实例,开启连接复用、设置超时、新增重试逻辑,减少连接开销和临时网络波动的影响:

const axios = require('axios')
const https = require('https')
// 创建复用的axios实例
const httpClient = axios.create({
  timeout: 15000, // 15秒超时
  // 开启keep-alive复用TCP连接,减少TLS握手开销
  httpsAgent: new https.Agent({
    keepAlive: true,
    maxSockets: 10, // 最大socket数和并发数对应
    // 仅当目标站点证书存在问题时开启以下配置,生产环境不建议开启
    // rejectUnauthorized: false
  }),
  headers: {
    // 模拟浏览器UA,避免被反爬拦截
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36'
  }
})

// 自定义请求重试方法,最多重试2次
async function requestWithRetry(url, retries = 2) {
  try {
    return await httpClient.get(url)
  } catch (err) {
    if (retries > 0) {
      // 重试前等待1秒,避免触发站点限流
      await new Promise(resolve => setTimeout(resolve, 1000))
      return requestWithRetry(url, retries - 1)
    }
    throw err
  }
}

// 修改内容提取函数的请求逻辑
async function scrapeContent(item) {
  try {
    let content = "";
    // 使用带重试的请求方法
    const { data } = await requestWithRetry(item.newsLink);

    const $ = cheerio.load(data);
    const listItems = $(item.selector);

    listItems.each((_, item) => {
      content += $(item).text();
    });

    return {
      ...item,
      content: content.replace(/[\r\n\"\t]+/gm, "")
    };
  } catch (error) {
    console.log({ in: "scrapeContent", link: item.newsLink, message: error.message });
    // 失败请求返回带错误标记的结果,避免最终结果出现undefined
    return {
      ...item,
      content: "",
      error: error.message
    }
  }
}

3. 额外优化建议

  • 如果目标站点反爬严格,可以在两次请求之间加随机的延迟时间,进一步降低被限流的概率
  • 并发数不要设置过高,建议先从5开始测试,慢慢上调到不报错的最大值

内容的提问来源于stack exchange,提问作者khaled taha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 11:36:05