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

Node.js v20+如何为特定URL的Fetch API全局设置代理Agent

问题:全局拦截fetch请求,为特定域名选择性添加代理Agent

是否可以全局拦截fetch请求,仅针对特定域名的fetch请求选择性传入agent?我希望能拦截依赖的第三方代码发起的fetch请求。示例伪代码如下:

https.globalAgent.on('request', (request) => {
  if(request.url.includes('microsoft.com')){
    // 伪代码思路:获取原始请求后,选择以下两种方式之一:
    // 1) 克隆并取消原始请求,用新的agent重新发起请求
    // 2) 直接修改原始请求,添加`agent`参数
    new Request(request.clone(), {agent: MY_CUSTOM_HTTPS_PROXY_AGENT})
  }
})

背景信息

  • 使用Node.js v20+版本
  • 依赖的第三方库会发起fetch请求到公网进行身份验证(例如microsoft.com)
  • 公司服务器仅允许向内部域名(如mycompany.com、test.mycompany.com等)发起HTTP请求,外部域名请求需通过代理转发

当前困境

使用的身份验证库会向microsoft.com发起fetch请求,该域名不在公司允许列表内。目前临时方案是复刻/分叉该认证库,在请求中添加代理Agent:

let response = await fetch("some_domain.com", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${accessToken}`,
  },
  agent: MY_CUSTOM_HTTPS_PROXY_AGENT // 🟡 在分叉的认证库中添加了这一行
});

但不想维护分叉版本避免版本不一致,未来考虑提交PR但因涉及两个依赖库修改且时间紧张暂时搁置。

以下是可用的自定义HTTPS代理代码:

import net from 'net';
import tls from 'tls';
import https from 'https';

/*
   @example
   const agent = new HttpsProxyAgent({
     proxy: { host: PROXY_HOST, port: PROXY_PORT },
     key: fs.readFileSync(KEY_PATH),
     cert: fs.readFileSync(CERT_PATH),
     ca: fs.readFileSync(CA_CERT_PATH),
    });
*/
class CustomHttpsProxyAgent extends https.Agent {
  constructor(options) {
    super(options);
    this.proxy = options.proxy;
    this.key = options.key;
    this.cert = options.cert;
    this.ca = options.ca;
  }

  createConnection(options, callback) {
    const proxySocket = net.connect(this.proxy);

    proxySocket.on('connect', () => {
      const connectRequest = `CONNECT ${options.host}:${options.port} HTTP/1.1\r\n\r\n`;
      proxySocket.write(connectRequest);

      proxySocket.once('data', () => {
        const tlsSocket = tls.connect({
          socket: proxySocket,
          servername: options.host,
          key: this.key,
          cert: this.cert,
          ca: this.ca,
        });

        callback(null, tlsSocket);
      });
    });
  }
}

export default CustomHttpsProxyAgent;

解决方案

在Node.js v20+中,你可以通过重写全局fetch函数实现全局拦截并选择性添加代理Agent,无需修改第三方库代码,这种方式能覆盖所有调用fetch的场景(包括第三方库发起的请求)。

步骤1:定义代理域名规则

先明确需要走代理的域名,编写判断逻辑:

const NEED_PROXY_DOMAINS = [
  'microsoft.com',
  // 可添加其他需要代理的外部域名
];

// 判断URL是否需要走代理的工具函数
function shouldUseProxy(url) {
  const urlObj = new URL(url);
  return NEED_PROXY_DOMAINS.some(domain => urlObj.hostname.endsWith(domain));
}

步骤2:初始化自定义代理Agent

根据提供的CustomHttpsProxyAgent代码,初始化实例:

import fs from 'fs';
import CustomHttpsProxyAgent from './path/to/CustomHttpsProxyAgent.js';

const PROXY_HOST = 'your-proxy-host';
const PROXY_PORT = 8080; // 替换为实际代理端口
const KEY_PATH = './path/to/key.pem';
const CERT_PATH = './path/to/cert.pem';
const CA_CERT_PATH = './path/to/ca.pem';

const MY_CUSTOM_HTTPS_PROXY_AGENT = new CustomHttpsProxyAgent({
  proxy: { host: PROXY_HOST, port: PROXY_PORT },
  key: fs.readFileSync(KEY_PATH),
  cert: fs.readFileSync(CERT_PATH),
  ca: fs.readFileSync(CA_CERT_PATH),
});

步骤3:重写全局fetch函数

保存原始fetch引用,包装成带代理逻辑的新函数:

// 保存原始fetch引用
const originalFetch = globalThis.fetch;

// 重写全局fetch
globalThis.fetch = async function(resource, options = {}) {
  // 提取请求URL:兼容字符串和Request对象两种传入方式
  const requestUrl = typeof resource === 'string' ? resource : resource.url;
  
  // 判断是否需要添加代理
  if (shouldUseProxy(requestUrl)) {
    const modifiedOptions = {
      ...options,
      agent: MY_CUSTOM_HTTPS_PROXY_AGENT
    };
    
    // Request对象不可变,需克隆后传入新配置
    if (resource instanceof Request) {
      return originalFetch(new Request(resource, modifiedOptions));
    } else {
      return originalFetch(resource, modifiedOptions);
    }
  }
  
  // 不需要代理的请求,直接调用原始fetch
  return originalFetch(resource, options);
};

关键注意事项

  1. 执行时机:这段重写代码必须在第三方库加载之前执行,确保所有fetch调用都经过包装。
  2. Request对象处理:若第三方库传入的是Request实例,必须通过new Request(resource, modifiedOptions)克隆修改,因为Request对象本身是不可变的。
  3. HTTP请求兼容:如果需要处理HTTP(非HTTPS)请求,可仿照CustomHttpsProxyAgent实现CustomHttpProxyAgent,并在判断逻辑中区分协议。
  4. 错误处理:可根据需求添加错误捕获逻辑,避免代理配置问题影响正常内部请求。

为什么不直接用https.globalAgent?

Node.js v20+的fetch底层基于undici库(而非传统http/https模块),监听https.globalAgent的事件无法拦截fetch请求,重写全局fetch是更可靠的方案。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 00:07:02