multi-protocol-proxy-chain
v1.0.4
Published
Chain multiple proxies (HTTP/HTTPS/SOCKS4/SOCKS5/SSH) in strict order for Node.js. 多协议链式代理库
Downloads
30
Maintainers
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.tsdeclarations - ✅ 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/SOCKS4与HTTP/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(可选) - 最大端口号,默认65535host:string(可选) - 绑定检测的主机地址,默认'127.0.0.1'
返回:
Promise<number>- 第一个可用的端口号
抛出:
- 如果从
initPort到maxPort范围内没有可用端口,抛出错误
示例:
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()确保所有服务器正确关闭 - 在应用退出时(如
SIGINT、SIGTERM)调用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 localhostQ: 可以同时启动多个本地入口吗?
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 地址是否为最后一个代理的出口 IPQ: 性能如何?
A: 每增加一级代理大约增加 50-200ms 延迟。对于大多数应用场景,3-5 级代理链是可以接受的。如果需要更高性能,建议:
- 减少代理链层级
- 选择地理位置较近的代理
- 使用更快的代理服务器
Q: 支持代理认证吗?
A: 支持。所有协议都支持用户名/密码认证(通过 userId 和 password 字段)。
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)
- ✅ 改进端口检测机制
- ✅ 完善文档和示例
