proxy-pool-manager
v1.0.8
Published
proxy manager
Readme
Proxy Manager SDK
一个功能强大的代理管理器 SDK,提供代理管理、HTTP 请求封装、自动代理轮换和健康检查等功能。
✨ 特性
- 🪶 轻量级模式:无需 MongoDB,仅使用请求和队列功能
- 🔄 智能代理管理:支持从 MongoDB 加载代理,自动验证和轮换(可选)
- 🌐 HTTP 请求封装:内置 HTTP 客户端,支持自动代理切换或直接指定代理
- 📊 代理健康检查:自动检测代理可用性,支持自定义检测规则(可选)
- 🎯 多种代理策略:支持顺序、随机、故障转移三种策略
- 📦 批量操作:支持批量插入和管理代理
- 🔍 日志系统:基于 Winston 的完整日志记录
- ⚡ 异步队列:高效的异步任务处理机制
- 🛡️ 类型安全:完整的 TypeScript 类型定义
📦 安装
npm install proxy-pool-manager🚀 快速开始
轻量级模式(推荐,无需 MongoDB)
如果你只需要使用 HTTP 请求和队列功能,不需要代理管理,可以使用轻量级模式:
import { createProxyRequest } from 'proxy-pool-manager';
// 创建轻量级 SDK 实例(不连接 MongoDB)
const sdk = await createProxyRequest({
maxRetries: 3,
timeout: 30,
logLevel: 'info'
});
// 发送 GET 请求
const response = await sdk.get('https://api.example.com/data', {
params: { page: 1 }
});
// 在请求中直接指定代理(可选)
const responseWithProxy = await sdk.post('http://your-api.com/request', {
url: 'https://api.example.com/data',
method: 'GET',
proxy: 'http://proxy.example.com:8080', // 直接指定代理
timeout: 10
});
console.log(response.data);轻量级模式 + 代理数组(支持异常时自动轮换)
如果你需要代理管理但不想连接 MongoDB,可以传入代理数组:
import { createProxyRequest } from 'proxy-pool-manager';
// 创建轻量级 SDK 实例 + 代理数组(不连接 MongoDB)
const sdk = await createProxyRequest({
proxies: [
'proxy1.example.com:8080:user1:pass1',
'proxy2.example.com:8080:user2:pass2',
'proxy3.example.com:8080:user3:pass3'
],
proxyStrategy: 'sequential', // 顺序策略
maxRetries: 3,
timeout: 30,
logLevel: 'info'
});
// 发送请求,会自动使用代理管理器选择的代理
// 如果代理失败,会自动轮换到下一个代理并重试
const response = await sdk.post('http://your-api.com/request', {
url: 'https://api.example.com/data',
method: 'GET',
timeout: 10
});
console.log('当前使用的代理:', sdk.getCurrentProxy());
console.log('可用代理列表:', sdk.getAvailableProxies());完整模式(包含代理管理功能)
如果需要代理管理功能(自动轮换、健康检查等),需要提供 MongoDB 连接:
import { createProxyRequest } from 'proxy-pool-manager';
// 创建完整 SDK 实例(包含代理管理)
const sdk = await createProxyRequest({
mongoUri: 'mongodb://localhost:27017/proxy_db',
proxyStrategy: 'sequential',
logLevel: 'info',
timeout: 30,
proxyCheckOptions: {
mainUrl: 'http://example.com/check',
timeout: 10,
}
});
// 发送 GET 请求(自动使用代理管理器选择的代理)
const response = await sdk.get('https://api.example.com/data', {
params: { page: 1 }
});
// 或者为特定请求指定代理(优先级高于自动选择)
const responseWithSpecificProxy = await sdk.post('http://your-api.com/request', {
url: 'https://api.example.com/data',
method: 'GET',
proxy: 'http://specific-proxy.com:8080', // 请求级代理优先
timeout: 10
});
console.log(response.data);完整模式 + 代理数组(支持异常时自动轮换)
如果需要代理管理功能,并且想预先设置代理列表:
import { createProxyRequest } from 'proxy-pool-manager';
// 创建完整 SDK 实例 + 代理数组(连接 MongoDB)
const sdk = await createProxyRequest({
mongoUri: 'mongodb://localhost:27017/proxy_db',
proxies: [
'proxy1.example.com:8080:user1:pass1',
'proxy2.example.com:8080:user2:pass2',
'proxy3.example.com:8080:user3:pass3'
],
proxyStrategy: 'failover', // 故障转移策略
maxRetries: 3,
timeout: 30,
proxyCheckOptions: {
mainUrl: 'http://example.com/check',
timeout: 10,
}
});
// 代理会被保存到 MongoDB,并支持自动轮换
// 如果请求失败,会自动轮换到下一个代理并重试
const response = await sdk.get('https://api.example.com/data');添加代理
// 添加单个代理
await sdk.addProxy('proxy.example.com:8080:username:password');
// 批量添加代理
const count = await sdk.bulkInsertProxies([
'proxy1.example.com:8080:user1:pass1',
'proxy2.example.com:8080:user2:pass2',
'proxy3.example.com:8080:user3:pass3',
]);
console.log(`成功添加 ${count} 个代理`);HTTP 请求方法
// GET 请求
const getResponse = await sdk.get('https://api.example.com/users', {
params: { page: 1, limit: 10 }
});
// POST 请求
const postResponse = await sdk.post('https://api.example.com/users', {
data: { name: 'John', email: '[email protected]' },
headers: { 'Content-Type': 'application/json' }
});
// PUT 请求
const putResponse = await sdk.put('https://api.example.com/users/1', {
data: { name: 'Jane' }
});
// DELETE 请求
const deleteResponse = await sdk.delete('https://api.example.com/users/1');
// PATCH 请求
const patchResponse = await sdk.patch('https://api.example.com/users/1', {
data: { status: 'active' }
});
// 自定义请求
const customResponse = await sdk.request({
url: 'https://api.example.com/custom',
method: 'POST',
options: {
data: { custom: 'data' },
timeout: 60,
proxy: 'specific-proxy.com:8080' // 使用特定代理
}
});📖 API 文档
ProxyRequestSDK
主 SDK 类,提供统一的 API 接口。
构造函数选项
interface SDKOptions {
mongoUri?: string; // MongoDB 连接 URI(可选,启用代理管理时需要)
maxRetries?: number; // 最大重试次数,默认 3
timeout?: number; // 请求超时时间(秒),默认 30
proxyStrategy?: ProxyStrategy; // 代理策略,默认 'sequential'
logLevel?: LogLevel; // 日志级别,默认 'info'
instanceId?: string; // 实例 ID,用于多实例场景
proxies?: string[]; // 代理数组,支持异常时自动轮换
proxy?: string; // 单个代理
retryDelay?: number; // 重试间隔(毫秒),默认使用指数退避策略
retryDelayBase?: number; // 指数退避的基础延迟(毫秒),默认 1000
retryDelayMultiplier?: number; // 指数退避的倍数,默认 2
proxyCheckEnabled?: boolean; // 是否启用代理检查,默认 true
proxyLimit?: number; // 代理加载限制,0 表示不加载,默认 0
proxyCheckOptions?: { // 代理检查配置(启用代理管理时需要)
mainUrl: string; // 代理检查主 URL(启用代理管理时必需)
testUrls?: string[]; // 额外的测试 URL
timeout?: number; // 检查超时时间(秒)
successStatusCodes?: number[]; // 成功状态码列表
checkInterval?: number; // 检查间隔(毫秒)
maxConsecutiveFails?: number; // 最大连续失败次数
maxResponseTime?: number; // 最大响应时间(毫秒)
};
}配置说明:
- 轻量级模式:不提供
mongoUri和proxyCheckOptions,SDK 将以轻量级模式运行,不连接 MongoDB,不初始化代理管理功能 - 轻量级模式 + 代理数组:提供
proxies或proxy但不提供mongoUri,SDK 将以轻量级模式运行,代理仅存储在内存中,支持异常时自动轮换 - 完整模式:提供
mongoUri或proxyCheckOptions,SDK 将启用代理管理功能 - 完整模式 + 代理数组:同时提供
mongoUri和proxies,代理会被保存到 MongoDB,并支持异常时自动轮换 - 禁用代理检查:设置
proxyCheckEnabled: false可禁用代理检查 - 不加载代理:设置
proxyLimit: 0可不从数据库加载代理
方法
请求方法
get<T>(url: string, params?: Record<string, string>, options?: RequestOptions): Promise<HttpResponse<T>>post<T>(url: string, options?: RequestOptions): Promise<HttpResponse<T>>put<T>(url: string, options?: RequestOptions): Promise<HttpResponse<T>>delete<T>(url: string, options?: RequestOptions): Promise<HttpResponse<T>>patch<T>(url: string, options?: RequestOptions): Promise<HttpResponse<T>>request<T>(config: RequestConfig): Promise<HttpResponse<T>>
代理管理方法(仅在启用代理管理功能时可用)
addProxy(proxyUrl: string): Promise<ProxyItem | null>- 添加代理deleteProxy(proxyUrl: string): Promise<boolean>- 删除代理getAvailableProxies(): string[]- 获取可用代理列表getCurrentProxy(): string | null- 获取当前使用的代理rotateProxy(): Promise<string | null>- 轮换到下一个代理setProxyStrategy(strategy: ProxyStrategy): void- 设置代理策略checkProxy(proxy?: string): Promise<boolean>- 检查代理可用性triggerProxyCheck(): Promise<void>- 触发代理检查getProxyDetails(proxyUrl: string): ProxyItem | undefined- 获取代理详情hasProxyManagement(): boolean- 检查是否启用了代理管理功能
批量操作
bulkInsertProxies(proxyUrls: string[]): Promise<number>- 批量插入代理
统计信息
getProxyStats(): Promise<ProxyStats>- 获取代理统计信息getQueueStats(): QueueStats- 获取队列统计信息
工具方法
waitForReady(): Promise<void>- 等待初始化完成setLogLevel(level: LogLevel): void- 设置日志级别getLogLevel(): LogLevel- 获取当前日志级别getInstanceId(): string- 获取实例 IDdestroy(): Promise<void>- 清理资源
代理策略
支持三种代理选择策略,每种策略都有不同的使用场景和特点:
1. sequential(顺序策略)
特点:
- 按照代理列表的顺序依次使用代理
- 每次请求后自动切换到下一个代理
- 简单、可预测,适合需要均匀分配请求的场景
使用场景:
- 需要均匀分配请求到各个代理
- 代理质量相近,不需要特别优化
- 需要可预测的代理使用顺序
示例:
const sdk = await createProxyRequest({
proxies: [
'proxy1.example.com:8080:user1:pass1',
'proxy2.example.com:8080:user2:pass2',
'proxy3.example.com:8080:user3:pass3'
],
proxyStrategy: 'sequential'
});
// 第一次请求使用 proxy1
const response1 = await sdk.get('https://api.example.com/data');
// 第二次请求使用 proxy2
const response2 = await sdk.get('https://api.example.com/data');
// 第三次请求使用 proxy3
const response3 = await sdk.get('https://api.example.com/data');
// 第四次请求又回到 proxy1(循环)轮换机制:
- 请求失败时,自动切换到下一个代理并重试
- 如果所有代理都失败,停止重试
2. random(随机策略)
特点:
- 从可用代理中随机选择一个使用
- 避免重复使用同一个代理,直到所有代理都被使用过
- 适合需要避免代理被过度使用的场景
使用场景:
- 需要避免某些代理被过度使用
- 代理质量相近,随机分配即可
- 需要分散请求负载
示例:
const sdk = await createProxyRequest({
proxies: [
'proxy1.example.com:8080:user1:pass1',
'proxy2.example.com:8080:user2:pass2',
'proxy3.example.com:8080:user3:pass3'
],
proxyStrategy: 'random'
});
// 每次请求随机选择一个代理
const response1 = await sdk.get('https://api.example.com/data');
const response2 = await sdk.get('https://api.example.com/data');
const response3 = await sdk.get('https://api.example.com/data');轮换机制:
- 随机选择代理,避免重复使用
- 当所有代理都被使用过后,重置使用记录
- 请求失败时,从剩余未使用的代理中随机选择并重试
3. failover(故障转移策略)⭐ 推荐
特点:
- 智能选择最佳可用代理
- 根据代理的历史表现(失败率、响应时间)自动选择最优代理
- 优先使用失败率低、响应时间短的代理
- 适合需要高可用性和性能的场景
- 不需要 MongoDB:统计信息存储在内存中,实时更新
选择优先级:
- 连续失败次数:优先选择连续失败次数最少的代理
- 失败率:在连续失败次数相同的情况下,选择失败率最低的代理
- 响应时间:在失败率相同的情况下,选择平均响应时间最短的代理
使用场景:
- 需要高可用性和性能的场景
- 代理质量差异较大,需要自动选择最优代理
- 需要自动排除故障代理
- 对请求成功率要求较高的场景
- 轻量级模式:不需要 MongoDB,仅使用内存统计
示例:
// 轻量级模式 + failover(不需要 MongoDB)
const sdk1 = await createProxyRequest({
proxies: [
'proxy1.example.com:8080:user1:pass1', // 高质量代理
'proxy2.example.com:8080:user2:pass2', // 中等质量代理
'proxy3.example.com:8080:user3:pass3' // 低质量代理
],
proxyStrategy: 'failover' // 不需要 MongoDB,统计信息存储在内存中
});
// 自动选择最优代理(失败率低、响应时间短)
const response = await sdk1.get('https://api.example.com/data');// 完整模式 + failover(使用 MongoDB 持久化统计信息)
const sdk2 = await createProxyRequest({
mongoUri: 'mongodb://localhost:27017/proxy_db',
proxies: [
'proxy1.example.com:8080:user1:pass1',
'proxy2.example.com:8080:user2:pass2',
'proxy3.example.com:8080:user3:pass3'
],
proxyStrategy: 'failover',
proxyCheckOptions: {
mainUrl: 'http://example.com/check'
}
});
// 统计信息会被持久化到 MongoDB,重启后仍然保留历史数据
const response = await sdk2.get('https://api.example.com/data');统计信息说明:
内存模式(不提供
mongoUri):- 统计信息存储在内存中,实时更新
- 重启后统计信息会重置
- 适合临时使用或单次运行场景
持久化模式(提供
mongoUri):- 统计信息会保存到 MongoDB
- 重启后仍然保留历史数据
- 适合长期运行或需要历史数据的场景
轮换机制:
- 请求失败时,自动标记当前代理的失败次数
- 下次请求时,自动选择表现最好的代理
- 连续失败超过阈值的代理会被标记为无效,不再使用
- 代理恢复后(成功请求),会自动重新启用
故障转移流程:
1. 选择最优代理(连续失败次数最少 → 失败率最低 → 响应时间最短)
2. 发送请求
3. 如果失败:
- 增加代理的失败计数
- 如果连续失败次数超过阈值,标记为无效
- 下次请求时自动选择下一个最优代理
4. 如果成功:
- 重置连续失败次数
- 更新平均响应时间
- 如果之前被标记为无效,自动恢复为有效状态性能优化:
- 自动排除故障代理,避免重复尝试
- 优先使用高质量代理,提高成功率
- 动态调整代理优先级,适应代理质量变化
重要说明:
- ✅ 不需要 MongoDB:failover 策略可以在轻量级模式下使用,统计信息存储在内存中
- ✅ 实时更新:每次请求后,统计信息会立即更新(成功/失败次数、响应时间等)
- ✅ 自动学习:随着请求的进行,系统会自动学习每个代理的质量,并优先使用高质量代理
- 💡 MongoDB 的作用:如果提供 MongoDB,统计信息会被持久化,重启后仍然保留历史数据,有助于更快地识别高质量代理
重试间隔配置
支持两种重试间隔策略:
1. 指数退避策略(默认)
每次重试前等待时间递增,适合大多数场景:
const sdk = await createProxyRequest({
maxRetries: 3,
retryDelayBase: 1000, // 基础延迟 1000ms(默认)
retryDelayMultiplier: 2 // 倍数 2(默认)
});
// 重试间隔:第1次 1000ms,第2次 2000ms,第3次 4000ms计算公式: waitTime = retryDelayBase × retryDelayMultiplier^(attempt-1)
示例:
- 第1次重试:1000ms × 2^0 = 1000ms
- 第2次重试:1000ms × 2^1 = 2000ms
- 第3次重试:1000ms × 2^2 = 4000ms
2. 固定间隔策略
每次重试前等待固定时间,适合需要稳定重试间隔的场景:
const sdk = await createProxyRequest({
maxRetries: 3,
retryDelay: 2000 // 每次重试都等待 2000ms
});
// 重试间隔:每次都是 2000ms使用场景:
- 指数退避:适合网络不稳定、需要避免服务器压力的场景
- 固定间隔:适合需要稳定重试节奏、便于调试的场景
自定义配置示例:
// 快速重试(500ms 基础,1.5倍递增)
const sdk1 = await createProxyRequest({
retryDelayBase: 500,
retryDelayMultiplier: 1.5
// 重试间隔:500ms → 750ms → 1125ms
});
// 慢速重试(2000ms 基础,2倍递增)
const sdk2 = await createProxyRequest({
retryDelayBase: 2000,
retryDelayMultiplier: 2
// 重试间隔:2000ms → 4000ms → 8000ms
});
// 固定间隔 3 秒
const sdk3 = await createProxyRequest({
retryDelay: 3000
// 重试间隔:每次都是 3000ms
});日志级别
none- 不记录日志error- 仅记录错误warn- 记录警告和错误info- 记录信息、警告和错误(默认)debug- 记录调试信息verbose- 记录所有详细信息
🔧 高级用法
使用场景选择
场景 1:仅需要 HTTP 请求功能(推荐轻量级模式)
// 不需要代理管理,只需要发送 HTTP 请求
const sdk = await createProxyRequest({
maxRetries: 3,
timeout: 30,
logLevel: 'info'
});
// 直接使用,无需 MongoDB
const response = await sdk.get('https://api.example.com/data');场景 2:需要临时使用代理
// 轻量级模式 + 直接指定代理
const sdk = await createProxyRequest({
maxRetries: 3,
timeout: 30
});
// 在请求中直接指定代理
const response = await sdk.post('http://your-api.com/request', {
url: 'https://api.example.com/data',
method: 'GET',
proxy: 'http://proxy.example.com:8080:user:pass' // 直接指定代理
});场景 2.5:使用代理数组 + 异常时自动轮换(推荐)
// 轻量级模式 + 代理数组(不连接 MongoDB)
const sdk = await createProxyRequest({
proxies: [
'proxy1.example.com:8080:user1:pass1',
'proxy2.example.com:8080:user2:pass2',
'proxy3.example.com:8080:user3:pass3'
],
proxyStrategy: 'failover', // 故障转移策略
maxRetries: 3,
timeout: 30
});
// 发送请求,如果代理失败会自动轮换到下一个代理
const response = await sdk.post('http://your-api.com/request', {
url: 'https://api.example.com/data',
method: 'GET',
timeout: 10
});场景 3:需要代理管理功能
// 完整模式,启用代理管理
const sdk = await createProxyRequest({
mongoUri: 'mongodb://localhost:27017/proxy_db',
proxyCheckOptions: {
mainUrl: 'http://example.com/check',
timeout: 10,
}
});
// 添加代理到管理器
await sdk.addProxy('proxy1.example.com:8080:user1:pass1');
// 自动使用代理管理器选择的代理
const response = await sdk.get('https://api.example.com/data');场景 4:禁用代理检查,但仍使用代理管理
// 使用代理管理,但禁用代理检查
const sdk = await createProxyRequest({
mongoUri: 'mongodb://localhost:27017/proxy_db',
proxyCheckEnabled: false, // 禁用代理检查
proxyLimit: 0, // 不加载代理
proxyCheckOptions: {
mainUrl: 'http://example.com/check', // 仍然需要提供(用于后续启用)
}
});
// 手动添加代理,不进行自动检查
await sdk.addProxy('proxy.example.com:8080:user:pass');多实例场景
import { initializeServices } from 'proxy-pool-manager';
// 创建多个独立的 SDK 实例
const sdk1 = await initializeServices({
mongoUri: 'mongodb://localhost:27017/proxy_db',
instanceId: 'instance-1',
proxyCheckOptions: {
mainUrl: 'http://example.com/check'
}
});
const sdk2 = await initializeServices({
mongoUri: 'mongodb://localhost:27017/proxy_db',
instanceId: 'instance-2',
proxyCheckOptions: {
mainUrl: 'http://example.com/check'
}
});自定义代理检查
const sdk = await createProxyRequest({
mongoUri: 'mongodb://localhost:27017/proxy_db',
proxyCheckOptions: {
mainUrl: 'https://httpbin.org/ip',
testUrls: [
'https://api.ipify.org?format=json',
'https://ipinfo.io/json'
],
timeout: 15,
successStatusCodes: [200, 201],
checkInterval: 60000, // 每分钟检查一次
maxConsecutiveFails: 3, // 连续失败3次后标记为无效
maxResponseTime: 5000 // 最大响应时间5秒
}
});代理使用方式
1. 强制直连(noProxy)
当某次请求需要完全不使用代理(包括所有重试)时,可传 noProxy: true。此时无论 createProxyRequest 是否配置了代理、是否传了请求级 proxy,该请求及重试都会直连。
// 本次请求及重试均不走代理
const response = await sdk.post('http://your-api.com/request', {
url: 'https://api.example.com/data',
method: 'GET',
noProxy: true, // 强制直连,优先级高于 proxy
timeout: 10
});2. 直接指定代理(轻量级模式和完整模式都支持)
// 为特定请求指定代理
const response = await sdk.post('http://your-api.com/request', {
url: 'https://api.example.com/data',
method: 'GET',
proxy: 'http://proxy.example.com:8080:user:pass', // 直接指定代理
timeout: 10
});3. 使用代理数组(支持异常时自动轮换)
// 创建 SDK 时传入代理数组
const sdk = await createProxyRequest({
proxies: [
'proxy1.example.com:8080:user1:pass1',
'proxy2.example.com:8080:user2:pass2',
'proxy3.example.com:8080:user3:pass3'
],
proxyStrategy: 'sequential', // 顺序策略
maxRetries: 3
});
// 发送请求,会自动使用代理管理器选择的代理
// 如果代理失败,会自动轮换到下一个代理并重试
const response = await sdk.post('http://your-api.com/request', {
url: 'https://api.example.com/data',
method: 'GET',
timeout: 10
});
// 查看当前使用的代理
console.log('当前代理:', sdk.getCurrentProxy());
console.log('可用代理:', sdk.getAvailableProxies());4. 自动使用代理管理器选择的代理(完整模式)
// 先添加代理到管理器
await sdk.addProxy('proxy1.example.com:8080:user1:pass1');
await sdk.addProxy('proxy2.example.com:8080:user2:pass2');
// 不指定代理,自动使用代理管理器选择的代理
const response = await sdk.post('http://your-api.com/request', {
url: 'https://api.example.com/data',
method: 'GET',
// 不指定 proxy,会自动使用 ProxyManager 选择的代理
timeout: 10
});5. 代理优先级
代理使用遵循以下优先级:
- 强制直连(
options.noProxy === true)- 最高优先级,该请求及所有重试均不使用代理 - 请求级代理(
options.proxy)- 指定时使用该代理 - 代理管理器自动选择 - 如果启用了代理管理且没有指定请求级代理
- 无代理 - 如果都没有,则直接请求(不使用代理)
6. 异常时自动轮换
当请求失败时(超时、连接错误等),系统会自动轮换到下一个代理并重试:
const sdk = await createProxyRequest({
proxies: [
'proxy1.example.com:8080:user1:pass1',
'proxy2.example.com:8080:user2:pass2',
'proxy3.example.com:8080:user3:pass3'
],
proxyStrategy: 'failover', // 推荐使用故障转移策略
maxRetries: 3 // 最多重试3次,每次失败会自动轮换代理
});
// 如果 proxy1 失败,会自动尝试 proxy2,再失败会尝试 proxy3
const response = await sdk.get('https://api.example.com/data');轮换机制说明:
- 只有在使用代理管理器选择的代理时才会轮换(如果请求中直接指定了代理,不会轮换)
- 支持两种重试间隔策略:
- 指数退避策略(默认):每次重试前等待时间递增,公式为
retryDelayBase × retryDelayMultiplier^(attempt-1)- 默认值:基础延迟 1000ms,倍数 2
- 示例:第1次重试等待 1000ms,第2次等待 2000ms,第3次等待 4000ms
- 固定间隔策略:设置
retryDelay后,每次重试前等待固定时间- 示例:设置
retryDelay: 2000,每次重试都等待 2000ms
- 示例:设置
- 指数退避策略(默认):每次重试前等待时间递增,公式为
- 支持三种代理策略,每种策略的轮换方式不同:
- sequential:按顺序切换到下一个代理
- random:从剩余未使用的代理中随机选择
- failover:自动选择表现最好的代理(推荐)
不同策略的轮换行为:
| 策略 | 首次选择 | 失败后轮换 | 特点 | |------|---------|-----------|------| | sequential | 第一个代理 | 按顺序切换到下一个 | 简单、可预测 | | random | 随机选择 | 从剩余代理中随机选择 | 分散负载 | | failover | 最优代理 | 选择下一个最优代理 | 智能、高效 ⭐ |
故障检测:
系统会自动检测以下类型的错误并触发代理轮换:
- 连接超时(TimeoutError)
- 连接被拒绝(ECONNREFUSED)
- 网络错误(网络相关关键词)
- HTTP 错误(根据配置)
代理状态管理:
- 连续失败超过阈值的代理会被标记为无效
- 无效代理不会参与选择,直到恢复
- 代理恢复后(成功请求),会自动重新启用
6. 检查代理管理功能状态
// 检查是否启用了代理管理功能
if (sdk.hasProxyManagement()) {
console.log('代理管理功能已启用');
// 可以使用代理管理相关方法
await sdk.addProxy('proxy.example.com:8080');
} else {
console.log('轻量级模式,仅支持直接指定代理');
// 只能通过 options.proxy 指定代理
}代理统计信息
const stats = await sdk.getProxyStats();
console.log({
total: stats.total, // 总代理数
valid: stats.valid, // 有效代理数
invalid: stats.invalid, // 无效代理数
available: stats.available // 可用代理数
});
// 获取队列统计
const queueStats = sdk.getQueueStats();
console.log({
length: queueStats.length, // 队列长度
running: queueStats.running, // 运行中任务数
concurrency: queueStats.concurrency, // 并发数
idle: queueStats.idle // 是否空闲
});批量插入代理
import { bulkInsertProxyUrls } from 'proxy-pool-manager';
const count = await bulkInsertProxyUrls({
mongoUri: 'mongodb://localhost:27017/proxy_db',
proxyUrls: [
'proxy1.com:8080:user1:pass1',
'proxy2.com:8080:user2:pass2',
// ... 更多代理
],
batchSize: 500, // 每批处理500个
concurrency: 4, // 并发4个批次
logLevel: 'info'
});
console.log(`成功插入 ${count} 个代理`);📋 异步队列使用
AsyncQueueSingleton 是一个强大的异步任务队列管理器,支持并发控制、优先级任务、多实例等特性。
队列快速开始
import { AsyncQueueSingleton } from 'proxy-pool-manager';
// 创建队列实例
const queue = AsyncQueueSingleton.getInstance('my-queue', {
concurrency: 3, // 并发数:同时执行3个任务
autoStart: true, // 自动开始执行
logLevel: 'info',
onDrain: () => {
console.log('所有任务完成!');
},
onError: (error) => {
console.error('任务执行错误:', error);
},
onSuccess: (result) => {
console.log('任务成功:', result);
}
});
// 添加单个任务
const result = await queue.add({ id: 1, name: '任务1' });
console.log('任务结果:', result);
// 批量添加任务
const tasks = [
{ id: 1, name: '任务1' },
{ id: 2, name: '任务2' },
{ id: 3, name: '任务3' }
];
const results = await queue.addBatch(tasks);
console.log('批量任务结果:', results);自定义任务处理器
// 创建队列并设置自定义处理器
const queue = AsyncQueueSingleton.getInstance('custom-queue', {
concurrency: 2,
logLevel: 'debug'
});
// 设置任务处理器
queue.setTaskHandler(async (task: any) => {
console.log(`处理任务: ${task.name}`);
// 模拟异步操作
await new Promise(resolve => setTimeout(resolve, task.duration));
// 返回处理结果
return {
taskId: task.id,
status: 'completed',
timestamp: new Date().toISOString()
};
});
// 添加任务
const result = await queue.add({ id: 1, name: '处理文件', duration: 1000 });
console.log(result);队列控制
const queue = AsyncQueueSingleton.getInstance('control-queue', {
concurrency: 2,
autoStart: false // 手动控制启动
});
// 添加任务(队列已暂停,不会立即执行)
const promise = queue.add({ id: 1, name: '任务1' });
// 暂停队列
queue.pause();
console.log('队列已暂停');
// 恢复队列
queue.resume();
console.log('队列已恢复');
// 等待任务完成
const result = await promise;优先级任务
const queue = AsyncQueueSingleton.getInstance('priority-queue', {
concurrency: 2
});
// 普通任务(priority = 0,默认)
await queue.add({ id: 1, name: '普通任务1' }, 0);
// 高优先级任务(priority > 0,会插入到队列前面)
await queue.add({ id: 2, name: '高优先级任务' }, 1);
// 最高优先级任务
await queue.add({ id: 3, name: '紧急任务' }, 2);队列状态监控
const queue = AsyncQueueSingleton.getInstance('monitor-queue');
// 获取队列统计信息
const stats = queue.stats;
console.log({
length: stats.length, // 队列中等待的任务数
running: stats.running, // 正在执行的任务数
concurrency: stats.concurrency, // 并发数
idle: stats.idle // 是否空闲
});
// 获取队列长度
console.log('队列长度:', queue.length);
// 获取运行中任务数
console.log('运行中任务:', queue.running);
// 检查队列是否空闲
if (queue.idle) {
console.log('队列空闲,所有任务已完成');
}多实例队列
// 创建不同类型的队列实例
const imageQueue = AsyncQueueSingleton.getInstance('image-processing', {
concurrency: 2,
taskHandler: async (task) => {
console.log(`处理图片: ${task.filename}`);
await new Promise(resolve => setTimeout(resolve, 2000));
return `图片处理完成: ${task.filename}`;
}
});
const dataQueue = AsyncQueueSingleton.getInstance('data-processing', {
concurrency: 5,
taskHandler: async (task) => {
console.log(`处理数据: ${task.id}`);
await new Promise(resolve => setTimeout(resolve, 500));
return `数据处理完成: ${task.id}`;
}
});
// 同时使用多个队列
const [imageResults, dataResults] = await Promise.all([
imageQueue.addBatch(imageTasks),
dataQueue.addBatch(dataTasks)
]);
// 获取所有实例名称
const instanceNames = AsyncQueueSingleton.getInstanceNames();
console.log('所有队列实例:', instanceNames);
// 获取所有实例的统计信息
const allStats = AsyncQueueSingleton.getAllInstancesStats();
console.log('所有队列统计:', allStats);动态调整并发数
const queue = AsyncQueueSingleton.getInstance('dynamic-queue', {
concurrency: 3
});
// 动态更新并发数
queue.updateConcurrency(5);
console.log('并发数已更新为:', queue.stats.concurrency);泛型支持
// 使用泛型指定返回类型
interface ApiResponse {
endpoint: string;
status: string;
data: any;
}
const apiQueue = AsyncQueueSingleton.getInstance<ApiResponse>('api-queue', {
concurrency: 3
});
apiQueue.setTaskHandler(async (task: any): Promise<ApiResponse> => {
// 模拟API请求
await new Promise(resolve => setTimeout(resolve, 1000));
return {
endpoint: task.url,
status: 'success',
data: { result: 'ok' }
};
});
const response = await apiQueue.add({ url: '/api/users' });
// response 的类型是 ApiResponse
console.log(response.endpoint, response.status);实际应用场景
1. API 请求限流
const apiQueue = AsyncQueueSingleton.getInstance('api-rate-limit', {
concurrency: 5 // 限制同时最多5个API请求
});
apiQueue.setTaskHandler(async (apiCall: any) => {
const response = await fetch(apiCall.url);
return await response.json();
});
// 添加多个API请求,自动限流
const results = await apiQueue.addBatch([
{ url: 'https://api.example.com/users' },
{ url: 'https://api.example.com/orders' },
{ url: 'https://api.example.com/products' }
]);2. 文件批量处理
const fileQueue = AsyncQueueSingleton.getInstance('file-processing', {
concurrency: 2,
onDrain: () => console.log('所有文件处理完成')
});
fileQueue.setTaskHandler(async (file: any) => {
// 处理文件
await processFile(file);
return `文件 ${file.name} 处理完成`;
});
const files = [
{ name: 'document1.pdf', size: 1024 },
{ name: 'image1.jpg', size: 2048 }
];
const results = await fileQueue.addBatch(files);3. 数据库操作队列
const dbQueue = AsyncQueueSingleton.getInstance('database-queue', {
concurrency: 1 // 串行执行,避免数据库锁冲突
});
dbQueue.setTaskHandler(async (operation: any) => {
// 执行数据库操作
await db.execute(operation);
return `操作完成: ${operation.type}`;
});
await dbQueue.add({ type: 'INSERT', table: 'users', data: {...} });队列清理
// 销毁指定队列实例
AsyncQueueSingleton.destroyInstance('my-queue');
// 销毁所有队列实例
AsyncQueueSingleton.destroyAllInstances();AsyncQueue API 参考
静态方法
getInstance<T>(name: string, options?: AsyncQueueOptions<T>): AsyncQueueSingleton<T>- 获取或创建队列实例getInstanceNames(): string[]- 获取所有实例名称getAllInstancesStats(): Record<string, QueueStats>- 获取所有实例统计信息hasInstance(name: string): boolean- 检查实例是否存在getExistingInstance<T>(name: string): AsyncQueueSingleton<T> | null- 获取已存在的实例destroyInstance(name: string): void- 销毁指定实例destroyAllInstances(): void- 销毁所有实例
实例方法
add(task: Task, priority?: number): Promise<T>- 添加任务addBatch(tasks: Task[], priority?: number): Promise<T[]>- 批量添加任务setTaskHandler(handler: (task: Task) => Promise<T>): void- 设置任务处理器updateConcurrency(newConcurrency: number): void- 更新并发数pause(): this- 暂停队列resume(): this- 恢复队列destroy(): void- 销毁队列setLogLevel(level: LogLevel): void- 设置日志级别getLogLevel(): LogLevel- 获取日志级别getName(): string- 获取实例名称
属性
length: number- 队列长度running: number- 运行中任务数idle: boolean- 是否空闲stats: QueueStats- 队列统计信息
配置选项
interface AsyncQueueOptions<T> {
concurrency?: number; // 并发数,默认 100
autoStart?: boolean; // 自动开始,默认 true
logLevel?: LogLevel; // 日志级别
onDrain?: () => void; // 队列排空回调
onError?: (error: Error) => void; // 错误回调
onSuccess?: (result: T) => void; // 成功回调
taskHandler?: (task: Task) => Promise<T>; // 任务处理器
}🗄️ MongoDB 数据结构
代理数据存储在 MongoDB 中,集合结构如下:
interface ProxyDocument {
url: string; // 代理 URL(格式:host:port:username:password)
totalRequests: number; // 总请求数
failCount: number; // 失败次数
avgResponseTime: number; // 平均响应时间(毫秒)
lastCheckTime: number; // 最后检查时间(时间戳)
consecutiveFails: number; // 连续失败次数
status: 'valid' | 'invalid'; // 状态
createdAt: Date; // 创建时间
updatedAt: Date; // 更新时间
}📝 类型定义
完整的 TypeScript 类型定义已包含在包中:
import type {
RequestOptions,
HttpResponse,
ProxyStrategy,
ProxyItem,
ProxyCheckOptions,
LogLevel
} from 'proxy-pool-manager';⚠️ 注意事项
轻量级模式 vs 完整模式:
- 轻量级模式:不提供
mongoUri和proxyCheckOptions,不连接 MongoDB,仅使用请求和队列功能 - 完整模式:提供
mongoUri或proxyCheckOptions,启用代理管理功能,需要 MongoDB 连接
- 轻量级模式:不提供
MongoDB 连接:仅在启用代理管理功能时需要,确保 MongoDB 服务正在运行且连接 URI 正确
代理格式:代理 URL 格式为
host:port:username:password或http://host:port:username:password代理使用:
- 轻量级模式下,只能通过
options.proxy直接指定代理 - 完整模式下,可以自动使用代理管理器选择的代理,也可以直接指定代理(优先级更高)
- 轻量级模式下,只能通过
初始化等待:SDK 初始化是异步的,使用
waitForReady()确保初始化完成资源清理:使用完毕后调用
destroy()方法清理资源并发限制:代理检查的并发数可通过
maxConcurrentChecks配置禁用功能:
- 设置
proxyCheckEnabled: false可禁用代理检查 - 设置
proxyLimit: 0可不从数据库加载代理
- 设置
