npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

multi-protocol-proxy-chain

v1.0.4

Published

Chain multiple proxies (HTTP/HTTPS/SOCKS4/SOCKS5/SSH) in strict order for Node.js. 多协议链式代理库

Downloads

30

Readme

multi-protocol-proxy-chain

Chain multiple proxies in strict order (HTTP/HTTPS/SOCKS4/SOCKS5/SSH) for Node.js. TypeScript-first library to build multi-hop forward proxy chains.

多协议链式代理库(HTTP/HTTPS/SOCKS4/SOCKS5/SSH),用于在 Node.js 中构建严格顺序的多跳前向代理链,提供 TypeScript 类型支持。

Features / 特性

  • Strict-order proxy chain: client → local → p0 → p1 → … → target
  • Multi-protocol support: HTTP, HTTPS, SOCKS5, SOCKS4, SSH (raw passthrough)
  • HTTP CONNECT tunneling and plain HTTP proxying
  • TypeScript types and .d.ts declarations
  • Async lifecycle: start() returns the actual bound URL; stopAll() awaits graceful shutdown
  • Port selection helper: auto-find available port from a start value
  • Cross-platform: Windows, macOS, Linux support
  • EventEmitter: Listen to connection errors and lifecycle events
  • Custom logger: Support custom logging functions

Use Cases / 适用场景

  • 通过多级上游代理实现分层转发与出站路由
  • SOCKS5/SOCKS4HTTP/HTTPS 混合链式连接
  • 在受限网络中通过 HTTP CONNECT 建立隧道
  • 将浏览器或 CLI 流量统一引导到本地入口后多跳转发

多协议链式代理库,支持严格顺序的代理链转发:

client -> local proxy -> proxies[0] -> proxies[1] -> ... -> target

安装

npm install multi-protocol-proxy-chain

系统要求

  • Node.js: >= 14.0.0
  • 操作系统: Windows 10+, macOS 10.14+, Linux (所有主流发行版)
  • 依赖: ssh2 (用于 SSH 代理支持)

跨平台支持

本库完全支持跨平台运行:

  • Windows: 使用 netstat -ano 进行端口检测
  • macOS: 使用 lsof 进行端口检测
  • Linux: 优先使用 ss 命令,回退到 lsof,最后使用绑定检测
  • 其他 Unix-like 系统: 使用通用的绑定检测方法

所有平台都支持自动端口查找和代理链功能。

快速开始

基础示例

import { MultiProtocolProxyChain } from 'multi-protocol-proxy-chain';

const chain = new MultiProtocolProxyChain();
chain.setProxies([
  { protocol: 'http', host: '192.168.101.166', port: 7890 },
  { protocol: 'socks5', host: '128.121.59.167', port: 36168, userId: 'user', password: 'pass' },
]);

// 启动本地入口(例如 socks5)
(async () => {
  try {
    const url = await chain.start('socks5', 2000);
    console.log('本地代理入口:', url);
    // 输出: socks5://127.0.0.1:2000 (或自动找到的可用端口)
  } catch (err) {
    console.error('启动失败:', err);
  }
})();

完整示例(包含错误处理和优雅关闭)

import { MultiProtocolProxyChain } from 'multi-protocol-proxy-chain';

const chain = new MultiProtocolProxyChain({
  logger: {
    log: (...args) => console.log('[ProxyChain]', ...args),
    error: (...args) => console.error('[ProxyChain Error]', ...args),
  },
});

// 设置代理链(严格按顺序)
chain.setProxies([
  { protocol: 'http', host: 'proxy1.example.com', port: 8080 },
  { protocol: 'socks5', host: 'proxy2.example.com', port: 1080, userId: 'user', password: 'pass' },
  { protocol: 'https', host: 'proxy3.example.com', port: 443, userId: 'user2', password: 'pass2' },
]);

// 监听错误事件
chain.on('error', (err) => {
  console.error('代理链错误:', err);
});

(async () => {
  try {
    // 启动本地 SOCKS5 代理入口
    const url = await chain.start('socks5', 2000, '127.0.0.1');
    console.log('✅ 本地代理入口已启动:', url);
    console.log('📝 使用示例:');
    console.log(`   curl --socks5-hostname 127.0.0.1:2000 https://httpbin.org/ip`);
    
    // 也可以启动多个不同协议的入口
    const httpUrl = await chain.start('http', 3128);
    console.log('✅ HTTP 代理入口:', httpUrl);
  } catch (err) {
    console.error('❌ 启动失败:', err);
    process.exit(1);
  }
})();

// 优雅关闭
process.on('SIGINT', async () => {
  console.log('\n收到退出信号,正在关闭代理入口...');
  await chain.stopAll();
  console.log('✅ 已关闭所有代理入口');
  process.exit(0);
});

process.on('SIGTERM', async () => {
  await chain.stopAll();
  process.exit(0);
});

使用不同协议的本地入口

const chain = new MultiProtocolProxyChain();
chain.setProxies([/* ... */]);

// 启动 SOCKS5 入口(浏览器常用)
const socks5Url = await chain.start('socks5', 2000);

// 启动 HTTP 入口(支持 CONNECT 和普通 HTTP 请求)
const httpUrl = await chain.start('http', 3128);

// 启动 HTTPS 入口(需要 TLS 证书,本库使用自签名证书)
const httpsUrl = await chain.start('https', 8443);

// 启动 SOCKS4 入口
const socks4Url = await chain.start('socks4', 1080);

错误处理示例

const chain = new MultiProtocolProxyChain();

try {
  // 尝试启动代理
  const url = await chain.start('socks5', 2000);
  console.log('启动成功:', url);
} catch (err) {
  if (err instanceof Error) {
    if (err.message.includes('EADDRINUSE')) {
      console.error('端口已被占用,尝试其他端口...');
      // 可以尝试其他端口或使用 PortOccupiedCheck
    } else if (err.message.includes('Unsupported')) {
      console.error('不支持的协议');
    } else {
      console.error('启动失败:', err.message);
    }
  }
}

监听连接事件

const chain = new MultiProtocolProxyChain();

// 监听代理链错误
chain.on('error', (err) => {
  console.error('代理链连接错误:', err.message);
  // 可以在这里实现重连逻辑
});

chain.setProxies([/* ... */]);
await chain.start('socks5', 2000);

API 文档

MultiProtocolProxyChain

构造函数

new MultiProtocolProxyChain(options?: {
  logger?: {
    log: (...args: any[]) => void;
    error: (...args: any[]) => void;
  };
})

参数:

  • options.logger (可选): 自定义日志函数,默认使用 console

示例:

const chain = new MultiProtocolProxyChain({
  logger: {
    log: (...args) => myLogger.info(...args),
    error: (...args) => myLogger.error(...args),
  },
});

setProxies(proxies: ProxySpec[])

设置上游代理链,顺序严格遵循数组顺序。每次调用会替换之前的代理链。

参数:

  • proxies: 代理配置数组,按顺序执行

示例:

chain.setProxies([
  { protocol: 'http', host: 'proxy1.com', port: 8080 },
  { protocol: 'socks5', host: 'proxy2.com', port: 1080, userId: 'user', password: 'pass' },
]);

start(protocol, port, host?): Promise<string>

启动本地代理入口服务器。

参数:

  • protocol: 'http' | 'https' | 'socks5' | 'socks4' | 'ssh' - 本地入口协议
  • port: number - 起始端口号(如果被占用会自动查找下一个可用端口)
  • host: string (可选) - 绑定地址,默认 '127.0.0.1'

返回:

  • Promise<string> - 返回实际绑定的代理 URL,例如 'socks5://127.0.0.1:2000'

示例:

const url = await chain.start('socks5', 2000);
// url: 'socks5://127.0.0.1:2000'

const url2 = await chain.start('http', 3128, '0.0.0.0');
// url2: 'http://0.0.0.0:3128'

stopAll(): Promise<void>

停止所有已启动的本地代理入口,等待所有服务器优雅关闭。

示例:

await chain.stopAll();
console.log('所有代理入口已关闭');

事件

MultiProtocolProxyChain 继承自 EventEmitter,支持以下事件:

  • 'error': 当代理链连接出错时触发
    chain.on('error', (err: Error) => {
      console.error('代理链错误:', err);
    });

ProxySpec 类型

type ProxySpec = {
  protocol: 'http' | 'https' | 'socks5' | 'socks4' | 'ssh';
  host: string;           // 代理服务器地址
  port: number;            // 代理服务器端口
  userId?: string;         // 认证用户名(可选)
  password?: string;       // 认证密码(可选)
};

协议说明:

  • http: HTTP 代理,支持 CONNECT 隧道和普通 HTTP 请求
  • https: HTTPS 代理(TLS 加密连接)
  • socks5: SOCKS5 代理,支持用户名/密码认证
  • socks4: SOCKS4 代理,支持用户名认证
  • ssh: SSH 隧道代理(使用 ssh2 库)

PortOccupiedCheck

端口占用检测工具类。

checkPort(initPort, maxPort?, host?): Promise<number>

检查并返回一个未被占用的端口号。

参数:

  • initPort: number - 起始端口号
  • maxPort: number (可选) - 最大端口号,默认 65535
  • host: string (可选) - 绑定检测的主机地址,默认 '127.0.0.1'

返回:

  • Promise<number> - 第一个可用的端口号

抛出:

  • 如果从 initPortmaxPort 范围内没有可用端口,抛出错误

示例:

import { PortOccupiedCheck } from 'multi-protocol-proxy-chain';

const checker = new PortOccupiedCheck();
const port = await checker.checkPort(2000, 2100); // 在 2000-2100 范围内查找
console.log('可用端口:', port);

使用场景示例

场景 1: 浏览器代理设置

const chain = new MultiProtocolProxyChain();
chain.setProxies([
  { protocol: 'http', host: 'corporate-proxy.com', port: 8080 },
  { protocol: 'socks5', host: 'exit-node.com', port: 1080 },
]);

const url = await chain.start('socks5', 2000);
console.log('在浏览器中设置 SOCKS5 代理:', url);
// 浏览器设置: SOCKS5 127.0.0.1:2000

场景 2: CLI 工具代理

const chain = new MultiProtocolProxyChain();
chain.setProxies([/* ... */]);

await chain.start('http', 3128);

// 使用 curl
// curl --proxy http://127.0.0.1:3128 https://example.com

// 使用环境变量
// export http_proxy=http://127.0.0.1:3128
// export https_proxy=http://127.0.0.1:3128

场景 3: Node.js 应用代理

import { HttpsProxyAgent } from 'https-proxy-agent';

const chain = new MultiProtocolProxyChain();
chain.setProxies([/* ... */]);

const url = await chain.start('http', 3128);
const agent = new HttpsProxyAgent(url);

// 在 axios 中使用
import axios from 'axios';
const response = await axios.get('https://api.example.com', {
  httpsAgent: agent,
});

场景 4: 多协议混合链

// 通过 HTTP 代理 -> SOCKS5 代理 -> HTTPS 代理 -> 目标
chain.setProxies([
  { protocol: 'http', host: 'proxy1.com', port: 8080 },
  { protocol: 'socks5', host: 'proxy2.com', port: 1080, userId: 'user', password: 'pass' },
  { protocol: 'https', host: 'proxy3.com', port: 443 },
]);

注意事项

代理链顺序

  • ⚠️ 重要: 代理链的顺序是严格的,数组中的第一个代理会先连接,然后依次连接后续代理
  • 确保代理链的顺序正确,错误的顺序可能导致连接失败

端口管理

  • start() 方法会自动查找可用端口,从指定的 port 开始,最大到 65535
  • 如果需要限制端口范围,建议先使用 PortOccupiedCheck.checkPort(initPort, maxPort) 获取端口
  • 在极端并发场景下,端口可能被抢占,建议使用 try/catch 处理错误并重试

安全性

  • ⚠️ HTTPS 代理: 默认 rejectUnauthorized: false,不验证上游 HTTPS 代理的证书
  • 生产环境建议根据安全需求调整 TLS 验证策略
  • SSH 代理需要正确的用户名和密码(或密钥)

错误处理

  • 代理链中的任何连接错误都会触发 error 事件
  • 建议监听 error 事件并实现适当的错误处理逻辑
  • 网络问题可能导致代理链中断,需要实现重连机制

性能考虑

  • 多级代理会增加延迟,每增加一级代理大约增加 50-200ms 延迟
  • 建议在生产环境中监控代理链的性能和可用性
  • 对于高并发场景,考虑使用连接池或限流机制

资源清理

  • 使用 stopAll() 确保所有服务器正确关闭
  • 在应用退出时(如 SIGINTSIGTERM)调用 stopAll()
  • 未正确关闭可能导致端口占用问题

端口占用检测(PortOccupiedCheck)

PortOccupiedCheck 是一个跨平台的端口可用性检测工具,支持:

  • 跨平台支持: Windows (netstat), macOS (lsof), Linux (ss/lsof)
  • 自动回退: 如果系统工具不可用,自动使用绑定检测方法
  • 从起始端口开始逐个尝试,返回第一个可用端口
  • 默认从 initPort 检查到 65535,可通过第二个参数设定上限
  • 已被 start() 内部使用用于自动寻找可用端口

使用示例:

import { MultiProtocolProxyChain, PortOccupiedCheck } from 'multi-protocol-proxy-chain';

// 方式一:先检测端口范围,再启动(推荐用于生产环境)
const checker = new PortOccupiedCheck();
try {
  const availablePort = await checker.checkPort(2000, 2100); // 限制在 2000-2100 范围内
  console.log('找到可用端口:', availablePort);
  
  const chain = new MultiProtocolProxyChain();
  chain.setProxies([
    { protocol: 'http', host: '192.168.101.166', port: 7890 },
  ]);
  
  const url = await chain.start('socks5', availablePort, '127.0.0.1');
  console.log('本地代理入口:', url); // 例如:socks5://127.0.0.1:2003
} catch (err) {
  console.error('端口检测失败:', err);
}

// 方式二:直接调用 start(内部会自动从起始端口查找可用端口)
const chain2 = new MultiProtocolProxyChain();
chain2.setProxies([/* ... */]);
const url2 = await chain2.start('socks5', 2000);
console.log('本地代理入口(自动选择):', url2);

跨平台端口检测机制:

  • Windows: 使用 netstat -ano 快速检测端口占用
  • macOS: 使用 lsof 命令检测端口占用
  • Linux: 优先使用 ss 命令,回退到 lsof,最后使用绑定检测
  • 其他平台: 使用通用的绑定检测方法(尝试绑定端口来判断是否可用)

所有平台在检测失败时都会自动回退到可靠的绑定检测方法,确保功能可用。

常见问题 (FAQ)

Q: 支持 IPv6 吗?

A: 是的,支持 IPv6 地址。在设置代理时可以使用 IPv6 地址,本地入口也支持绑定到 IPv6 地址。

await chain.start('socks5', 2000, '::1'); // IPv6 localhost

Q: 可以同时启动多个本地入口吗?

A: 可以,可以多次调用 start() 启动不同协议或端口的入口。

await chain.start('socks5', 2000);
await chain.start('http', 3128);
await chain.start('socks5', 2001); // 甚至可以启动多个相同协议的入口

Q: 代理链中的某个代理连接失败会怎样?

A: 连接失败会触发 error 事件,并可能导致整个请求失败。建议监听 error 事件并实现重试或降级逻辑。

Q: 如何验证代理链是否正常工作?

A: 可以使用以下方法测试:

# 使用 curl 测试 SOCKS5 代理
curl --socks5-hostname 127.0.0.1:2000 https://httpbin.org/ip

# 使用 curl 测试 HTTP 代理
curl --proxy http://127.0.0.1:3128 https://httpbin.org/ip

# 检查返回的 IP 地址是否为最后一个代理的出口 IP

Q: 性能如何?

A: 每增加一级代理大约增加 50-200ms 延迟。对于大多数应用场景,3-5 级代理链是可以接受的。如果需要更高性能,建议:

  • 减少代理链层级
  • 选择地理位置较近的代理
  • 使用更快的代理服务器

Q: 支持代理认证吗?

A: 支持。所有协议都支持用户名/密码认证(通过 userIdpassword 字段)。

chain.setProxies([
  { protocol: 'http', host: 'proxy.com', port: 8080, userId: 'user', password: 'pass' },
  { protocol: 'socks5', host: 'proxy2.com', port: 1080, userId: 'user2', password: 'pass2' },
]);

许可证

ISC

贡献

欢迎提交 Issue 和 Pull Request!

更新日志

v1.0.4

  • ✅ 添加跨平台支持(Windows/macOS/Linux)
  • ✅ 改进端口检测机制
  • ✅ 完善文档和示例