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

如何DRY地扩展Node.js的http.Agent与https.Agent并复用含super的方法?

解决方案:用高阶函数封装通用逻辑

要给http.Agent和它的子类https.Agent同时添加并发限制逻辑,又要符合DRY原则,最合理的方式是用高阶函数封装通用的并发限制代码,动态生成继承自目标Agent类的子类。这样既不用重复编写逻辑,又能让super正确指向原Agent类的方法。

实现步骤

1. 编写高阶生成函数

这个函数接收一个Agent基类(可以是http.Agent或https.Agent),返回一个带有并发限制逻辑的子类:

function createConcurrencyLimitedAgent(BaseAgent) {
  return class ConcurrencyLimitedAgent extends BaseAgent {
    constructor(options = {}) {
      super(options);
      // 存储每个目标(host:port)的当前并发请求数
      this._activeRequests = new Map();
      // 默认并发上限,可通过options传入
      this.maxConcurrent = options.maxConcurrent || 10;

      // 监听socket释放事件,减少对应目标的并发计数
      this.on('free', (socket) => {
        const targetKey = `${socket.remoteAddress}:${socket.remotePort}`;
        const currentCount = this._activeRequests.get(targetKey);
        if (currentCount && currentCount > 0) {
          this._activeRequests.set(targetKey, currentCount - 1);
        }
      });
    }

    addRequest(req, options) {
      // 生成目标唯一标识(用host+port区分)
      const targetKey = `${options.host}:${options.port}`;
      const currentCount = this._activeRequests.get(targetKey) || 0;

      if (currentCount < this.maxConcurrent) {
        // 更新并发计数
        this._activeRequests.set(targetKey, currentCount + 1);
        // 调用原Agent的addRequest方法
        super.addRequest(req, options);
      } else {
        // 无容量时直接触发请求错误,避免排队
        req.emit('error', new Error(`Reached max concurrent requests for ${targetKey}`));
      }
    }
  };
}

2. 生成带限制的Agent类

针对http.Agent和https.Agent分别生成子类:

const http = require('http');
const https = require('https');

// 生成http版本的并发限制Agent
const LimitedHttpAgent = createConcurrencyLimitedAgent(http.Agent);
// 生成https版本的并发限制Agent
const LimitedHttpsAgent = createConcurrencyLimitedAgent(https.Agent);

3. 使用示例

// 初始化http代理,设置最大并发为5
const httpAgent = new LimitedHttpAgent({ maxConcurrent: 5 });
// 初始化https代理,设置最大并发为5
const httpsAgent = new LimitedHttpsAgent({ maxConcurrent: 5 });

// 发起http请求时使用代理
http.get('http://example.com', { agent: httpAgent }, (res) => {
  // 处理响应
}).on('error', (err) => {
  console.error('请求被拒绝:', err.message);
});

// 发起https请求时使用代理
https.get('https://example.com', { agent: httpsAgent }, (res) => {
  // 处理响应
}).on('error', (err) => {
  console.error('请求被拒绝:', err.message);
});

方案优势

  • 完全符合DRY原则:并发限制的核心逻辑只编写一次,复用所有Agent子类
  • super调用正常工作:生成的子类直接继承自目标Agent类,super.addRequest会正确调用原类的方法
  • 保留原类特性:生成的LimitedAgent仍然是原Agent的子类,继承所有原生属性和方法
  • 灵活配置:可以通过构造函数参数自定义并发上限

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 02:12:08