proxy-pool-manager 1.0.9 → 1.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -294
- package/dist/Request.d.ts +4 -0
- package/dist/Request.d.ts.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +13 -27
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +0 -3
- package/dist/proxyManager.d.ts +8 -35
- package/dist/proxyManager.d.ts.map +1 -1
- package/dist/types.d.ts +2 -7
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -2
- package/dist/ProxyUrlBulkInsertManager.d.ts +0 -38
- package/dist/ProxyUrlBulkInsertManager.d.ts.map +0 -1
- package/dist/mongoUtils.d.ts +0 -71
- package/dist/mongoUtils.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -4,12 +4,11 @@
|
|
|
4
4
|
|
|
5
5
|
## ✨ 特性
|
|
6
6
|
|
|
7
|
-
- 🪶
|
|
8
|
-
- 🔄
|
|
7
|
+
- 🪶 **内存代理**:代理列表由 `proxies` 传入,只保存在进程内存中
|
|
8
|
+
- 🔄 **可选轮换**:`rotateOnError: true` 时,上游代理失败才换下一条;默认关闭,重试沿用本次代理
|
|
9
9
|
- 🌐 **HTTP 请求封装**:内置 HTTP 客户端,支持自动代理切换或直接指定代理
|
|
10
10
|
- 📊 **代理健康检查**:自动检测代理可用性,支持自定义检测规则(可选)
|
|
11
11
|
- 🎯 **多种代理策略**:支持顺序、随机、故障转移三种策略
|
|
12
|
-
- 📦 **批量操作**:支持批量插入和管理代理
|
|
13
12
|
- 🔍 **日志系统**:基于 Winston 的完整日志记录
|
|
14
13
|
- ⚡ **异步队列**:高效的异步任务处理机制
|
|
15
14
|
- 🛡️ **类型安全**:完整的 TypeScript 类型定义
|
|
@@ -22,58 +21,54 @@ npm install proxy-pool-manager
|
|
|
22
21
|
|
|
23
22
|
## 🚀 快速开始
|
|
24
23
|
|
|
25
|
-
###
|
|
24
|
+
### 只发请求
|
|
26
25
|
|
|
27
|
-
|
|
26
|
+
不需要代理池时,只创建请求客户端:
|
|
28
27
|
|
|
29
28
|
```typescript
|
|
30
29
|
import { createProxyRequest } from 'proxy-pool-manager';
|
|
31
30
|
|
|
32
|
-
// 创建轻量级 SDK 实例(不连接 MongoDB)
|
|
33
31
|
const sdk = await createProxyRequest({
|
|
34
32
|
maxRetries: 3,
|
|
35
33
|
timeout: 30,
|
|
36
34
|
logLevel: 'info'
|
|
37
35
|
});
|
|
38
36
|
|
|
39
|
-
// 发送 GET 请求
|
|
40
37
|
const response = await sdk.get('https://api.example.com/data', {
|
|
41
38
|
params: { page: 1 }
|
|
42
39
|
});
|
|
43
40
|
|
|
44
|
-
// 在请求中直接指定代理(可选)
|
|
45
41
|
const responseWithProxy = await sdk.post('http://your-api.com/request', {
|
|
46
42
|
url: 'https://api.example.com/data',
|
|
47
43
|
method: 'GET',
|
|
48
|
-
proxy: 'http://proxy.example.com:8080',
|
|
44
|
+
proxy: 'http://proxy.example.com:8080',
|
|
49
45
|
timeout: 10
|
|
50
46
|
});
|
|
51
47
|
|
|
52
48
|
console.log(response.data);
|
|
53
49
|
```
|
|
54
50
|
|
|
55
|
-
###
|
|
51
|
+
### 传入代理数组
|
|
56
52
|
|
|
57
|
-
|
|
53
|
+
失败后换下一条需要 `rotateOnError: true`,默认关闭。
|
|
54
|
+
|
|
55
|
+
代理只存在当前进程内存中,进程退出后清空。
|
|
58
56
|
|
|
59
57
|
```typescript
|
|
60
58
|
import { createProxyRequest } from 'proxy-pool-manager';
|
|
61
59
|
|
|
62
|
-
// 创建轻量级 SDK 实例 + 代理数组(不连接 MongoDB)
|
|
63
60
|
const sdk = await createProxyRequest({
|
|
64
61
|
proxies: [
|
|
65
62
|
'proxy1.example.com:8080:user1:pass1',
|
|
66
63
|
'proxy2.example.com:8080:user2:pass2',
|
|
67
64
|
'proxy3.example.com:8080:user3:pass3'
|
|
68
65
|
],
|
|
69
|
-
proxyStrategy: 'sequential',
|
|
66
|
+
proxyStrategy: 'sequential',
|
|
70
67
|
maxRetries: 3,
|
|
71
68
|
timeout: 30,
|
|
72
69
|
logLevel: 'info'
|
|
73
70
|
});
|
|
74
71
|
|
|
75
|
-
// 发送请求,会自动使用代理管理器选择的代理
|
|
76
|
-
// 如果代理失败,会自动轮换到下一个代理并重试
|
|
77
72
|
const response = await sdk.post('http://your-api.com/request', {
|
|
78
73
|
url: 'https://api.example.com/data',
|
|
79
74
|
method: 'GET',
|
|
@@ -84,84 +79,10 @@ console.log('当前使用的代理:', sdk.getCurrentProxy());
|
|
|
84
79
|
console.log('可用代理列表:', sdk.getAvailableProxies());
|
|
85
80
|
```
|
|
86
81
|
|
|
87
|
-
###
|
|
88
|
-
|
|
89
|
-
如果需要代理管理功能(自动轮换、健康检查等),需要提供 MongoDB 连接:
|
|
90
|
-
|
|
91
|
-
```typescript
|
|
92
|
-
import { createProxyRequest } from 'proxy-pool-manager';
|
|
93
|
-
|
|
94
|
-
// 创建完整 SDK 实例(包含代理管理)
|
|
95
|
-
const sdk = await createProxyRequest({
|
|
96
|
-
mongoUri: 'mongodb://localhost:27017/proxy_db',
|
|
97
|
-
proxyStrategy: 'sequential',
|
|
98
|
-
logLevel: 'info',
|
|
99
|
-
timeout: 30,
|
|
100
|
-
proxyCheckOptions: {
|
|
101
|
-
mainUrl: 'http://example.com/check',
|
|
102
|
-
timeout: 10,
|
|
103
|
-
}
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
// 发送 GET 请求(自动使用代理管理器选择的代理)
|
|
107
|
-
const response = await sdk.get('https://api.example.com/data', {
|
|
108
|
-
params: { page: 1 }
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
// 或者为特定请求指定代理(优先级高于自动选择)
|
|
112
|
-
const responseWithSpecificProxy = await sdk.post('http://your-api.com/request', {
|
|
113
|
-
url: 'https://api.example.com/data',
|
|
114
|
-
method: 'GET',
|
|
115
|
-
proxy: 'http://specific-proxy.com:8080', // 请求级代理优先
|
|
116
|
-
timeout: 10
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
console.log(response.data);
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
### 完整模式 + 代理数组(支持异常时自动轮换)
|
|
123
|
-
|
|
124
|
-
如果需要代理管理功能,并且想预先设置代理列表:
|
|
125
|
-
|
|
126
|
-
```typescript
|
|
127
|
-
import { createProxyRequest } from 'proxy-pool-manager';
|
|
128
|
-
|
|
129
|
-
// 创建完整 SDK 实例 + 代理数组(连接 MongoDB)
|
|
130
|
-
const sdk = await createProxyRequest({
|
|
131
|
-
mongoUri: 'mongodb://localhost:27017/proxy_db',
|
|
132
|
-
proxies: [
|
|
133
|
-
'proxy1.example.com:8080:user1:pass1',
|
|
134
|
-
'proxy2.example.com:8080:user2:pass2',
|
|
135
|
-
'proxy3.example.com:8080:user3:pass3'
|
|
136
|
-
],
|
|
137
|
-
proxyStrategy: 'failover', // 故障转移策略
|
|
138
|
-
maxRetries: 3,
|
|
139
|
-
timeout: 30,
|
|
140
|
-
proxyCheckOptions: {
|
|
141
|
-
mainUrl: 'http://example.com/check',
|
|
142
|
-
timeout: 10,
|
|
143
|
-
}
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
// 代理会被保存到 MongoDB,并支持自动轮换
|
|
147
|
-
// 如果请求失败,会自动轮换到下一个代理并重试
|
|
148
|
-
const response = await sdk.get('https://api.example.com/data');
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
### 添加代理
|
|
82
|
+
### 追加代理
|
|
152
83
|
|
|
153
84
|
```typescript
|
|
154
|
-
// 添加单个代理
|
|
155
85
|
await sdk.addProxy('proxy.example.com:8080:username:password');
|
|
156
|
-
|
|
157
|
-
// 批量添加代理
|
|
158
|
-
const count = await sdk.bulkInsertProxies([
|
|
159
|
-
'proxy1.example.com:8080:user1:pass1',
|
|
160
|
-
'proxy2.example.com:8080:user2:pass2',
|
|
161
|
-
'proxy3.example.com:8080:user3:pass3',
|
|
162
|
-
]);
|
|
163
|
-
|
|
164
|
-
console.log(`成功添加 ${count} 个代理`);
|
|
165
86
|
```
|
|
166
87
|
|
|
167
88
|
### HTTP 请求方法
|
|
@@ -213,21 +134,20 @@ const customResponse = await sdk.request({
|
|
|
213
134
|
|
|
214
135
|
```typescript
|
|
215
136
|
interface SDKOptions {
|
|
216
|
-
mongoUri?: string; // MongoDB 连接 URI(可选,启用代理管理时需要)
|
|
217
137
|
maxRetries?: number; // 最大重试次数,默认 3
|
|
218
138
|
timeout?: number; // 请求超时时间(秒),默认 30
|
|
219
139
|
proxyStrategy?: ProxyStrategy; // 代理策略,默认 'sequential'
|
|
220
140
|
logLevel?: LogLevel; // 日志级别,默认 'info'
|
|
221
141
|
instanceId?: string; // 实例 ID,用于多实例场景
|
|
222
|
-
proxies?: string[]; //
|
|
142
|
+
proxies?: string[]; // 代理数组,只保存在内存中
|
|
223
143
|
proxy?: string; // 单个代理
|
|
224
144
|
retryDelay?: number; // 重试间隔(毫秒),默认使用指数退避策略
|
|
225
145
|
retryDelayBase?: number; // 指数退避的基础延迟(毫秒),默认 1000
|
|
226
146
|
retryDelayMultiplier?: number; // 指数退避的倍数,默认 2
|
|
147
|
+
rotateOnError?: boolean; // 上游代理失败时换下一条,默认 false
|
|
227
148
|
proxyCheckEnabled?: boolean; // 是否启用代理检查,默认 true
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
mainUrl: string; // 代理检查主 URL(启用代理管理时必需)
|
|
149
|
+
proxyCheckOptions?: { // 代理检查配置(启用健康检查时需要)
|
|
150
|
+
mainUrl: string; // 代理检查主 URL(启用代理检查时必需)
|
|
231
151
|
testUrls?: string[]; // 额外的测试 URL
|
|
232
152
|
timeout?: number; // 检查超时时间(秒)
|
|
233
153
|
successStatusCodes?: number[]; // 成功状态码列表
|
|
@@ -240,12 +160,9 @@ interface SDKOptions {
|
|
|
240
160
|
|
|
241
161
|
**配置说明:**
|
|
242
162
|
|
|
243
|
-
-
|
|
244
|
-
-
|
|
245
|
-
-
|
|
246
|
-
- **完整模式 + 代理数组**:同时提供 `mongoUri` 和 `proxies`,代理会被保存到 MongoDB,并支持异常时自动轮换
|
|
247
|
-
- **禁用代理检查**:设置 `proxyCheckEnabled: false` 可禁用代理检查
|
|
248
|
-
- **不加载代理**:设置 `proxyLimit: 0` 可不从数据库加载代理
|
|
163
|
+
- 不传 `proxies` / `proxy` / `proxyCheckOptions` 时,只提供 HTTP 请求,不启用代理池
|
|
164
|
+
- 传入 `proxies` 或 `proxy` 后启用代理池,列表只在内存中
|
|
165
|
+
- 设置 `proxyCheckEnabled: false` 可禁用代理健康检查
|
|
249
166
|
|
|
250
167
|
#### 方法
|
|
251
168
|
|
|
@@ -271,10 +188,6 @@ interface SDKOptions {
|
|
|
271
188
|
- `getProxyDetails(proxyUrl: string): ProxyItem | undefined` - 获取代理详情
|
|
272
189
|
- `hasProxyManagement(): boolean` - 检查是否启用了代理管理功能
|
|
273
190
|
|
|
274
|
-
##### 批量操作
|
|
275
|
-
|
|
276
|
-
- `bulkInsertProxies(proxyUrls: string[]): Promise<number>` - 批量插入代理
|
|
277
|
-
|
|
278
191
|
##### 统计信息
|
|
279
192
|
|
|
280
193
|
- `getProxyStats(): Promise<ProxyStats>` - 获取代理统计信息
|
|
@@ -376,7 +289,7 @@ const response3 = await sdk.get('https://api.example.com/data');
|
|
|
376
289
|
- 根据代理的历史表现(失败率、响应时间)自动选择最优代理
|
|
377
290
|
- 优先使用失败率低、响应时间短的代理
|
|
378
291
|
- 适合需要高可用性和性能的场景
|
|
379
|
-
-
|
|
292
|
+
- 统计信息只存在内存中,进程重启后清空
|
|
380
293
|
|
|
381
294
|
**选择优先级:**
|
|
382
295
|
|
|
@@ -390,55 +303,25 @@ const response3 = await sdk.get('https://api.example.com/data');
|
|
|
390
303
|
- 代理质量差异较大,需要自动选择最优代理
|
|
391
304
|
- 需要自动排除故障代理
|
|
392
305
|
- 对请求成功率要求较高的场景
|
|
393
|
-
- **轻量级模式**:不需要 MongoDB,仅使用内存统计
|
|
394
306
|
|
|
395
307
|
**示例:**
|
|
396
308
|
|
|
397
309
|
```typescript
|
|
398
|
-
|
|
399
|
-
const sdk1 = await createProxyRequest({
|
|
400
|
-
proxies: [
|
|
401
|
-
'proxy1.example.com:8080:user1:pass1', // 高质量代理
|
|
402
|
-
'proxy2.example.com:8080:user2:pass2', // 中等质量代理
|
|
403
|
-
'proxy3.example.com:8080:user3:pass3' // 低质量代理
|
|
404
|
-
],
|
|
405
|
-
proxyStrategy: 'failover' // 不需要 MongoDB,统计信息存储在内存中
|
|
406
|
-
});
|
|
407
|
-
|
|
408
|
-
// 自动选择最优代理(失败率低、响应时间短)
|
|
409
|
-
const response = await sdk1.get('https://api.example.com/data');
|
|
410
|
-
```
|
|
411
|
-
|
|
412
|
-
```typescript
|
|
413
|
-
// 完整模式 + failover(使用 MongoDB 持久化统计信息)
|
|
414
|
-
const sdk2 = await createProxyRequest({
|
|
415
|
-
mongoUri: 'mongodb://localhost:27017/proxy_db',
|
|
310
|
+
const sdk = await createProxyRequest({
|
|
416
311
|
proxies: [
|
|
417
312
|
'proxy1.example.com:8080:user1:pass1',
|
|
418
313
|
'proxy2.example.com:8080:user2:pass2',
|
|
419
314
|
'proxy3.example.com:8080:user3:pass3'
|
|
420
315
|
],
|
|
421
|
-
proxyStrategy: 'failover'
|
|
422
|
-
proxyCheckOptions: {
|
|
423
|
-
mainUrl: 'http://example.com/check'
|
|
424
|
-
}
|
|
316
|
+
proxyStrategy: 'failover'
|
|
425
317
|
});
|
|
426
318
|
|
|
427
|
-
|
|
428
|
-
const response = await sdk2.get('https://api.example.com/data');
|
|
319
|
+
const response = await sdk.get('https://api.example.com/data');
|
|
429
320
|
```
|
|
430
321
|
|
|
431
322
|
**统计信息说明:**
|
|
432
323
|
|
|
433
|
-
|
|
434
|
-
- 统计信息存储在内存中,实时更新
|
|
435
|
-
- 重启后统计信息会重置
|
|
436
|
-
- 适合临时使用或单次运行场景
|
|
437
|
-
|
|
438
|
-
- **持久化模式**(提供 `mongoUri`):
|
|
439
|
-
- 统计信息会保存到 MongoDB
|
|
440
|
-
- 重启后仍然保留历史数据
|
|
441
|
-
- 适合长期运行或需要历史数据的场景
|
|
324
|
+
失败次数和响应时间只记在内存里,进程重启后重新计算。
|
|
442
325
|
|
|
443
326
|
**轮换机制:**
|
|
444
327
|
|
|
@@ -470,10 +353,8 @@ const response = await sdk2.get('https://api.example.com/data');
|
|
|
470
353
|
|
|
471
354
|
**重要说明:**
|
|
472
355
|
|
|
473
|
-
-
|
|
474
|
-
-
|
|
475
|
-
- ✅ **自动学习**:随着请求的进行,系统会自动学习每个代理的质量,并优先使用高质量代理
|
|
476
|
-
- 💡 **MongoDB 的作用**:如果提供 MongoDB,统计信息会被持久化,重启后仍然保留历史数据,有助于更快地识别高质量代理
|
|
356
|
+
- 每次请求后统计会立即更新
|
|
357
|
+
- 连续失败超过阈值的代理会被标成无效,成功后再恢复
|
|
477
358
|
|
|
478
359
|
### 重试间隔配置
|
|
479
360
|
|
|
@@ -564,84 +445,23 @@ const sdk = await createProxyRequest({
|
|
|
564
445
|
logLevel: 'info'
|
|
565
446
|
});
|
|
566
447
|
|
|
567
|
-
//
|
|
448
|
+
// 不传 proxies 时只发请求
|
|
568
449
|
const response = await sdk.get('https://api.example.com/data');
|
|
569
450
|
```
|
|
570
451
|
|
|
571
|
-
#### 场景 2
|
|
452
|
+
#### 场景 2:单次请求指定代理
|
|
572
453
|
|
|
573
454
|
```typescript
|
|
574
|
-
// 轻量级模式 + 直接指定代理
|
|
575
455
|
const sdk = await createProxyRequest({
|
|
576
456
|
maxRetries: 3,
|
|
577
457
|
timeout: 30
|
|
578
458
|
});
|
|
579
459
|
|
|
580
|
-
// 在请求中直接指定代理
|
|
581
460
|
const response = await sdk.post('http://your-api.com/request', {
|
|
582
461
|
url: 'https://api.example.com/data',
|
|
583
462
|
method: 'GET',
|
|
584
|
-
proxy: 'http://proxy.example.com:8080:user:pass'
|
|
585
|
-
});
|
|
586
|
-
```
|
|
587
|
-
|
|
588
|
-
#### 场景 2.5:使用代理数组 + 异常时自动轮换(推荐)
|
|
589
|
-
|
|
590
|
-
```typescript
|
|
591
|
-
// 轻量级模式 + 代理数组(不连接 MongoDB)
|
|
592
|
-
const sdk = await createProxyRequest({
|
|
593
|
-
proxies: [
|
|
594
|
-
'proxy1.example.com:8080:user1:pass1',
|
|
595
|
-
'proxy2.example.com:8080:user2:pass2',
|
|
596
|
-
'proxy3.example.com:8080:user3:pass3'
|
|
597
|
-
],
|
|
598
|
-
proxyStrategy: 'failover', // 故障转移策略
|
|
599
|
-
maxRetries: 3,
|
|
600
|
-
timeout: 30
|
|
601
|
-
});
|
|
602
|
-
|
|
603
|
-
// 发送请求,如果代理失败会自动轮换到下一个代理
|
|
604
|
-
const response = await sdk.post('http://your-api.com/request', {
|
|
605
|
-
url: 'https://api.example.com/data',
|
|
606
|
-
method: 'GET',
|
|
607
|
-
timeout: 10
|
|
608
|
-
});
|
|
609
|
-
```
|
|
610
|
-
|
|
611
|
-
#### 场景 3:需要代理管理功能
|
|
612
|
-
|
|
613
|
-
```typescript
|
|
614
|
-
// 完整模式,启用代理管理
|
|
615
|
-
const sdk = await createProxyRequest({
|
|
616
|
-
mongoUri: 'mongodb://localhost:27017/proxy_db',
|
|
617
|
-
proxyCheckOptions: {
|
|
618
|
-
mainUrl: 'http://example.com/check',
|
|
619
|
-
timeout: 10,
|
|
620
|
-
}
|
|
621
|
-
});
|
|
622
|
-
|
|
623
|
-
// 添加代理到管理器
|
|
624
|
-
await sdk.addProxy('proxy1.example.com:8080:user1:pass1');
|
|
625
|
-
|
|
626
|
-
// 自动使用代理管理器选择的代理
|
|
627
|
-
const response = await sdk.get('https://api.example.com/data');
|
|
628
|
-
```
|
|
629
|
-
|
|
630
|
-
#### 场景 4:禁用代理检查,但仍使用代理管理
|
|
631
|
-
|
|
632
|
-
```typescript
|
|
633
|
-
// 使用代理管理,但禁用代理检查
|
|
634
|
-
const sdk = await createProxyRequest({
|
|
635
|
-
mongoUri: 'mongodb://localhost:27017/proxy_db',
|
|
636
|
-
proxyCheckEnabled: false, // 禁用代理检查
|
|
637
|
-
proxyLimit: 0, // 不加载代理
|
|
638
|
-
proxyCheckOptions: {
|
|
639
|
-
mainUrl: 'http://example.com/check', // 仍然需要提供(用于后续启用)
|
|
640
|
-
}
|
|
463
|
+
proxy: 'http://proxy.example.com:8080:user:pass'
|
|
641
464
|
});
|
|
642
|
-
|
|
643
|
-
// 手动添加代理,不进行自动检查
|
|
644
|
-
await sdk.addProxy('proxy.example.com:8080:user:pass');
|
|
645
465
|
```
|
|
646
466
|
|
|
647
467
|
### 多实例场景
|
|
@@ -649,21 +469,14 @@ await sdk.addProxy('proxy.example.com:8080:user:pass');
|
|
|
649
469
|
```typescript
|
|
650
470
|
import { initializeServices } from 'proxy-pool-manager';
|
|
651
471
|
|
|
652
|
-
// 创建多个独立的 SDK 实例
|
|
653
472
|
const sdk1 = await initializeServices({
|
|
654
|
-
|
|
655
|
-
instanceId: 'instance-1'
|
|
656
|
-
proxyCheckOptions: {
|
|
657
|
-
mainUrl: 'http://example.com/check'
|
|
658
|
-
}
|
|
473
|
+
proxies: ['proxy1.example.com:8080:user1:pass1'],
|
|
474
|
+
instanceId: 'instance-1'
|
|
659
475
|
});
|
|
660
476
|
|
|
661
477
|
const sdk2 = await initializeServices({
|
|
662
|
-
|
|
663
|
-
instanceId: 'instance-2'
|
|
664
|
-
proxyCheckOptions: {
|
|
665
|
-
mainUrl: 'http://example.com/check'
|
|
666
|
-
}
|
|
478
|
+
proxies: ['proxy2.example.com:8080:user2:pass2'],
|
|
479
|
+
instanceId: 'instance-2'
|
|
667
480
|
});
|
|
668
481
|
```
|
|
669
482
|
|
|
@@ -671,7 +484,7 @@ const sdk2 = await initializeServices({
|
|
|
671
484
|
|
|
672
485
|
```typescript
|
|
673
486
|
const sdk = await createProxyRequest({
|
|
674
|
-
|
|
487
|
+
proxies: ['proxy1.example.com:8080:user1:pass1'],
|
|
675
488
|
proxyCheckOptions: {
|
|
676
489
|
mainUrl: 'https://httpbin.org/ip',
|
|
677
490
|
testUrls: [
|
|
@@ -680,9 +493,9 @@ const sdk = await createProxyRequest({
|
|
|
680
493
|
],
|
|
681
494
|
timeout: 15,
|
|
682
495
|
successStatusCodes: [200, 201],
|
|
683
|
-
checkInterval: 60000,
|
|
684
|
-
maxConsecutiveFails: 3,
|
|
685
|
-
maxResponseTime: 5000
|
|
496
|
+
checkInterval: 60000,
|
|
497
|
+
maxConsecutiveFails: 3,
|
|
498
|
+
maxResponseTime: 5000
|
|
686
499
|
}
|
|
687
500
|
});
|
|
688
501
|
```
|
|
@@ -703,7 +516,7 @@ const response = await sdk.post('http://your-api.com/request', {
|
|
|
703
516
|
});
|
|
704
517
|
```
|
|
705
518
|
|
|
706
|
-
#### 2.
|
|
519
|
+
#### 2. 直接指定代理
|
|
707
520
|
|
|
708
521
|
```typescript
|
|
709
522
|
// 为特定请求指定代理
|
|
@@ -715,7 +528,7 @@ const response = await sdk.post('http://your-api.com/request', {
|
|
|
715
528
|
});
|
|
716
529
|
```
|
|
717
530
|
|
|
718
|
-
#### 3.
|
|
531
|
+
#### 3. 使用代理数组
|
|
719
532
|
|
|
720
533
|
```typescript
|
|
721
534
|
// 创建 SDK 时传入代理数组
|
|
@@ -729,8 +542,8 @@ const sdk = await createProxyRequest({
|
|
|
729
542
|
maxRetries: 3
|
|
730
543
|
});
|
|
731
544
|
|
|
732
|
-
//
|
|
733
|
-
//
|
|
545
|
+
// 发送请求,会使用代理管理器选择的代理
|
|
546
|
+
// 换下一条需要 rotateOnError: true
|
|
734
547
|
const response = await sdk.post('http://your-api.com/request', {
|
|
735
548
|
url: 'https://api.example.com/data',
|
|
736
549
|
method: 'GET',
|
|
@@ -742,7 +555,7 @@ console.log('当前代理:', sdk.getCurrentProxy());
|
|
|
742
555
|
console.log('可用代理:', sdk.getAvailableProxies());
|
|
743
556
|
```
|
|
744
557
|
|
|
745
|
-
#### 4.
|
|
558
|
+
#### 4. 自动使用代理池选出的代理
|
|
746
559
|
|
|
747
560
|
```typescript
|
|
748
561
|
// 先添加代理到管理器
|
|
@@ -769,7 +582,7 @@ const response = await sdk.post('http://your-api.com/request', {
|
|
|
769
582
|
|
|
770
583
|
#### 6. 异常时自动轮换
|
|
771
584
|
|
|
772
|
-
|
|
585
|
+
默认不换代理。设置 `rotateOnError: true` 后,网关返回的上游代理错误(代理认证、SOCKS、连接被拒绝、超时)才会换下一条并重试。连不上本次请求 URL 本身(网关不可达)不会记到代理凭证上。
|
|
773
586
|
|
|
774
587
|
```typescript
|
|
775
588
|
const sdk = await createProxyRequest({
|
|
@@ -779,7 +592,8 @@ const sdk = await createProxyRequest({
|
|
|
779
592
|
'proxy3.example.com:8080:user3:pass3'
|
|
780
593
|
],
|
|
781
594
|
proxyStrategy: 'failover', // 推荐使用故障转移策略
|
|
782
|
-
|
|
595
|
+
rotateOnError: true,
|
|
596
|
+
maxRetries: 3 // 最多重试3次,开启 rotateOnError 后每次上游代理失败会换下一条
|
|
783
597
|
});
|
|
784
598
|
|
|
785
599
|
// 如果 proxy1 失败,会自动尝试 proxy2,再失败会尝试 proxy3
|
|
@@ -810,12 +624,11 @@ const response = await sdk.get('https://api.example.com/data');
|
|
|
810
624
|
|
|
811
625
|
**故障检测:**
|
|
812
626
|
|
|
813
|
-
|
|
627
|
+
`rotateOnError: true` 时,按网关响应体判断上游代理失败并换凭证:
|
|
814
628
|
|
|
815
|
-
-
|
|
816
|
-
-
|
|
817
|
-
-
|
|
818
|
-
- HTTP 错误(根据配置)
|
|
629
|
+
- 代理认证失败(407)
|
|
630
|
+
- 响应里带有 proxy / socks / tunnel
|
|
631
|
+
- 状态码 408、502、503,且错误文案是超时、连接被拒绝、域名无法解析
|
|
819
632
|
|
|
820
633
|
**代理状态管理:**
|
|
821
634
|
|
|
@@ -858,26 +671,6 @@ console.log({
|
|
|
858
671
|
});
|
|
859
672
|
```
|
|
860
673
|
|
|
861
|
-
### 批量插入代理
|
|
862
|
-
|
|
863
|
-
```typescript
|
|
864
|
-
import { bulkInsertProxyUrls } from 'proxy-pool-manager';
|
|
865
|
-
|
|
866
|
-
const count = await bulkInsertProxyUrls({
|
|
867
|
-
mongoUri: 'mongodb://localhost:27017/proxy_db',
|
|
868
|
-
proxyUrls: [
|
|
869
|
-
'proxy1.com:8080:user1:pass1',
|
|
870
|
-
'proxy2.com:8080:user2:pass2',
|
|
871
|
-
// ... 更多代理
|
|
872
|
-
],
|
|
873
|
-
batchSize: 500, // 每批处理500个
|
|
874
|
-
concurrency: 4, // 并发4个批次
|
|
875
|
-
logLevel: 'info'
|
|
876
|
-
});
|
|
877
|
-
|
|
878
|
-
console.log(`成功插入 ${count} 个代理`);
|
|
879
|
-
```
|
|
880
|
-
|
|
881
674
|
## 📋 异步队列使用
|
|
882
675
|
|
|
883
676
|
`AsyncQueueSingleton` 是一个强大的异步任务队列管理器,支持并发控制、优先级任务、多实例等特性。
|
|
@@ -1207,24 +1000,6 @@ interface AsyncQueueOptions<T> {
|
|
|
1207
1000
|
}
|
|
1208
1001
|
```
|
|
1209
1002
|
|
|
1210
|
-
## 🗄️ MongoDB 数据结构
|
|
1211
|
-
|
|
1212
|
-
代理数据存储在 MongoDB 中,集合结构如下:
|
|
1213
|
-
|
|
1214
|
-
```typescript
|
|
1215
|
-
interface ProxyDocument {
|
|
1216
|
-
url: string; // 代理 URL(格式:host:port:username:password)
|
|
1217
|
-
totalRequests: number; // 总请求数
|
|
1218
|
-
failCount: number; // 失败次数
|
|
1219
|
-
avgResponseTime: number; // 平均响应时间(毫秒)
|
|
1220
|
-
lastCheckTime: number; // 最后检查时间(时间戳)
|
|
1221
|
-
consecutiveFails: number; // 连续失败次数
|
|
1222
|
-
status: 'valid' | 'invalid'; // 状态
|
|
1223
|
-
createdAt: Date; // 创建时间
|
|
1224
|
-
updatedAt: Date; // 更新时间
|
|
1225
|
-
}
|
|
1226
|
-
```
|
|
1227
|
-
|
|
1228
1003
|
## 📝 类型定义
|
|
1229
1004
|
|
|
1230
1005
|
完整的 TypeScript 类型定义已包含在包中:
|
|
@@ -1242,24 +1017,10 @@ import type {
|
|
|
1242
1017
|
|
|
1243
1018
|
## ⚠️ 注意事项
|
|
1244
1019
|
|
|
1245
|
-
1.
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
4. **代理使用**:
|
|
1254
|
-
- 轻量级模式下,只能通过 `options.proxy` 直接指定代理
|
|
1255
|
-
- 完整模式下,可以自动使用代理管理器选择的代理,也可以直接指定代理(优先级更高)
|
|
1256
|
-
|
|
1257
|
-
5. **初始化等待**:SDK 初始化是异步的,使用 `waitForReady()` 确保初始化完成
|
|
1258
|
-
|
|
1259
|
-
6. **资源清理**:使用完毕后调用 `destroy()` 方法清理资源
|
|
1260
|
-
|
|
1261
|
-
7. **并发限制**:代理检查的并发数可通过 `maxConcurrentChecks` 配置
|
|
1262
|
-
|
|
1263
|
-
8. **禁用功能**:
|
|
1264
|
-
- 设置 `proxyCheckEnabled: false` 可禁用代理检查
|
|
1265
|
-
- 设置 `proxyLimit: 0` 可不从数据库加载代理
|
|
1020
|
+
1. **代理池**:传入 `proxies` 或 `proxy` 后启用。列表和失败计数只在内存中,进程退出后清空。不传则只发 HTTP 请求。
|
|
1021
|
+
2. **代理格式**:`host:port:username:password`,或 `http://user:pass@host:port`
|
|
1022
|
+
3. **代理使用**:请求级 `options.proxy` 优先于代理池自动选择;`noProxy: true` 强制直连。
|
|
1023
|
+
4. **初始化等待**:SDK 初始化是异步的,使用 `waitForReady()` 确保初始化完成
|
|
1024
|
+
5. **资源清理**:使用完毕后调用 `destroy()` 方法清理资源
|
|
1025
|
+
6. **并发限制**:代理检查的并发数可通过 `maxConcurrentChecks` 配置
|
|
1026
|
+
7. **禁用健康检查**:设置 `proxyCheckEnabled: false`
|
package/dist/Request.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export declare class Request {
|
|
|
9
9
|
private readonly retryDelay;
|
|
10
10
|
private readonly retryDelayBase;
|
|
11
11
|
private readonly retryDelayMultiplier;
|
|
12
|
+
private readonly rotateOnError;
|
|
12
13
|
constructor(options?: RequestInitOptions);
|
|
13
14
|
/**
|
|
14
15
|
* 设置日志等级
|
|
@@ -53,6 +54,9 @@ export declare class Request {
|
|
|
53
54
|
* 检查是否启用了代理管理功能
|
|
54
55
|
*/
|
|
55
56
|
hasProxyManagement(): boolean;
|
|
57
|
+
private shouldSwitchCredential;
|
|
58
|
+
private noteCredentialFailure;
|
|
59
|
+
private waitBeforeRetry;
|
|
56
60
|
}
|
|
57
61
|
export default Request;
|
|
58
62
|
//# sourceMappingURL=Request.d.ts.map
|
package/dist/Request.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Request.d.ts","sourceRoot":"","sources":["../src/Request.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,aAAa,EACb,cAAc,EACd,kBAAkB,EAClB,YAAY,EAEZ,UAAU,EACV,QAAQ,EACT,MAAM,SAAS,CAAC;AAIjB,qBAAa,OAAO;IAClB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;IAC9C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,YAAY,CAAoB;IACxC,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAgB;IAC3C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAS;
|
|
1
|
+
{"version":3,"file":"Request.d.ts","sourceRoot":"","sources":["../src/Request.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,aAAa,EACb,cAAc,EACd,kBAAkB,EAClB,YAAY,EAEZ,UAAU,EACV,QAAQ,EACT,MAAM,SAAS,CAAC;AAIjB,qBAAa,OAAO;IAClB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;IAC9C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,YAAY,CAAoB;IACxC,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAgB;IAC3C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAS;IAC9C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAU;gBAG5B,OAAO,GAAE,kBAAuB;IA0C5C;;KAEC;IACM,WAAW,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI;IAUzC;;OAEG;IACI,WAAW,IAAI,QAAQ;IAS9B;;MAEE;IACF,OAAO,CAAC,GAAG;IAiBX,eAAe;YACD,WAAW;IAuCzB;;OAEG;YACW,oBAAoB;IAgGlC,sBAAsB;IACtB,OAAO,CAAC,iBAAiB;IAMZ,GAAG,CAAC,CAAC,EAChB,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAed,IAAI,CAAC,CAAC,EACjB,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAQd,GAAG,CAAC,CAAC,EAChB,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAQd,MAAM,CAAC,CAAC,EACnB,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAQd,KAAK,CAAC,CAAC,EAClB,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAQ3B,aAAa;IACA,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE;QAC9B,GAAG,EAAE,MAAM,CAAC;QACZ,MAAM,EAAE,UAAU,CAAC;QACnB,OAAO,EAAE,cAAc,CAAA;KACxB,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAoF5B,mBAAmB;IACnB,OAAO,CAAC,aAAa;IAkBd,eAAe,IAAI,MAAM,GAAG,IAAI;IAO1B,WAAW,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAO3C,eAAe,IAAI,IAAI;IAOvB,gBAAgB,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI;IAOzC,UAAU,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAOlD,uBAAuB,IAAI,MAAM,EAAE;IAO1C;;OAEG;IACI,kBAAkB,IAAI,OAAO;IAIpC,OAAO,CAAC,sBAAsB;IAO9B,OAAO,CAAC,qBAAqB;YAMf,eAAe;CAW9B;AAgCD,eAAe,OAAO,CAAC"}
|