@wiajs/request 3.0.37 → 3.0.39
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/dist/request.cjs +82 -12
- package/dist/request.mjs +82 -12
- package/lib/request.js +81 -11
- package/package.json +1 -1
package/dist/request.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* wia request v3.0.
|
|
2
|
+
* wia request v3.0.39
|
|
3
3
|
* (c) 2022-2025 Sibyl Yu and contributors
|
|
4
4
|
* Released under the MIT License.
|
|
5
5
|
*/
|
|
@@ -525,24 +525,88 @@ let Request = class Request extends stream.Duplex {
|
|
|
525
525
|
// agents 优于 agent
|
|
526
526
|
if (agents) {
|
|
527
527
|
const scheme = protocol.slice(0, -1);
|
|
528
|
-
opt.agent
|
|
528
|
+
// [FIX] 仅当 agents 中存在对应协议的 agent 时才覆盖 opt.agent
|
|
529
|
+
// 防止 agents['https'] 为空时将 opt.agent 覆盖为 undefined,导致回退到 globalAgent
|
|
530
|
+
if (agents[scheme]) opt.agent = agents[scheme];
|
|
529
531
|
// http 非隧道代理模式,模块以代理主机为准,其他以目的网址为准
|
|
530
532
|
// 代理内部会根据代理协议选择 http(s) 发起请求创建连接
|
|
531
533
|
if (protocol === 'http:' && agents.http) {
|
|
532
|
-
|
|
534
|
+
// 注意:这里修改的是局部变量 protocol,用于选择 httpModule
|
|
535
|
+
// protocol 以proxy协议为准
|
|
536
|
+
const { proxy } = agents.http;
|
|
537
|
+
if (proxy && !agents.http.tunnel) protocol = proxy.protocol;
|
|
533
538
|
}
|
|
534
539
|
// log({scheme, agents, protocol}, 'request')
|
|
535
540
|
}
|
|
536
541
|
const httpModule = httpModules[protocol];
|
|
537
542
|
if (!httpModule) throw TypeError(`Unsupported protocol: ${protocol}`);
|
|
538
|
-
//
|
|
539
|
-
//
|
|
540
|
-
//
|
|
543
|
+
// ============================================================
|
|
544
|
+
// [FIX] 针对 Bun 的终极修复:构建纯净的 Request Options
|
|
545
|
+
// ============================================================
|
|
546
|
+
// 1. 定义标准 Node.js http.request 接受的字段白名单
|
|
547
|
+
// 避免传入 agents, followRedirects 等杂质干扰 Bun 的解析
|
|
548
|
+
const nativeFields = [
|
|
549
|
+
'agent',
|
|
550
|
+
'auth',
|
|
551
|
+
'createConnection',
|
|
552
|
+
'defaultPort',
|
|
553
|
+
'family',
|
|
554
|
+
'headers',
|
|
555
|
+
'hints',
|
|
556
|
+
'host',
|
|
557
|
+
'hostname',
|
|
558
|
+
'insecureHTTPParser',
|
|
559
|
+
'localAddress',
|
|
560
|
+
'localPort',
|
|
561
|
+
'lookup',
|
|
562
|
+
'maxHeaderSize',
|
|
563
|
+
'method',
|
|
564
|
+
'path',
|
|
565
|
+
'port',
|
|
566
|
+
'protocol',
|
|
567
|
+
'rejectUnauthorized',
|
|
568
|
+
'servername',
|
|
569
|
+
'setHost',
|
|
570
|
+
'socketPath',
|
|
571
|
+
'timeout',
|
|
572
|
+
'signal'
|
|
573
|
+
];
|
|
574
|
+
// 2. 创建纯净的 options 对象
|
|
575
|
+
const reqOpt = {};
|
|
576
|
+
// 3. 显式拷贝字段 (同时也解决了 [Object: null prototype] 问题)
|
|
577
|
+
for (const field of nativeFields){
|
|
578
|
+
if (opt[field] !== undefined) reqOpt[field] = opt[field];
|
|
579
|
+
}
|
|
580
|
+
// 端口修正逻辑 (保持不变)
|
|
581
|
+
if (!reqOpt.port) reqOpt.port = protocol === 'https:' ? 443 : 80;
|
|
582
|
+
else if (reqOpt.port) reqOpt.port = Number(reqOpt.port);
|
|
583
|
+
// 再次显式确保 agent 存在于新对象中 (防御性编程)
|
|
584
|
+
// if (opt.agent) reqOpt.agent = opt.agent
|
|
585
|
+
// ============================================================
|
|
586
|
+
// [FIX] 针对 Bun 的强制代理修复
|
|
587
|
+
// ============================================================
|
|
588
|
+
if (opt.agent) {
|
|
589
|
+
// 1. 仍然赋值 agent,以便 Node.js 环境正常工作
|
|
590
|
+
reqOpt.agent = opt.agent;
|
|
591
|
+
// 2. 【关键】针对 Bun:直接将 Agent 的创建连接方法暴露给 Request
|
|
592
|
+
// Bun 的 http.request 可能忽略 agent 对象,但通常会尊重 createConnection 选项
|
|
593
|
+
reqOpt.createConnection = (args, cb)=>{
|
|
594
|
+
log$1({
|
|
595
|
+
args
|
|
596
|
+
}, 'Direct createConnection triggered via options');
|
|
597
|
+
// 强制调用你的 Agent 的 createConnection
|
|
598
|
+
// 注意:需要确保 this 上下文正确指向 opt.agent
|
|
599
|
+
return opt.agent.createConnection(args, cb);
|
|
600
|
+
};
|
|
601
|
+
}
|
|
541
602
|
log$1({
|
|
542
|
-
|
|
543
|
-
|
|
603
|
+
reqOpt,
|
|
604
|
+
protocol,
|
|
605
|
+
agentType: reqOpt.agent ? 'custom' : 'global'
|
|
544
606
|
}, 'request');
|
|
545
|
-
|
|
607
|
+
// Create the native request and set up its event handlers
|
|
608
|
+
// @ts-ignore
|
|
609
|
+
const req = httpModule.request(reqOpt, m._onResponse);
|
|
546
610
|
m._currentRequest = req;
|
|
547
611
|
// @ts-ignore
|
|
548
612
|
req.redirectReq = m;
|
|
@@ -551,7 +615,8 @@ let Request = class Request extends stream.Duplex {
|
|
|
551
615
|
// set tcp keep alive to prevent drop connection by peer
|
|
552
616
|
req.on('socket', /** @param {*} socket */ (socket)=>{
|
|
553
617
|
// default interval of sending ack packet is 1 minute
|
|
554
|
-
socket
|
|
618
|
+
// [FIX] 增加 socket 存在性检查,防止极少数情况下的 race condition
|
|
619
|
+
if (socket) socket.setKeepAlive(true, 1000 * 60);
|
|
555
620
|
});
|
|
556
621
|
// 请求error单独处理
|
|
557
622
|
// 'error' 事件处理,避免错误将冒泡到全局导致程序崩溃
|
|
@@ -560,8 +625,9 @@ let Request = class Request extends stream.Duplex {
|
|
|
560
625
|
;
|
|
561
626
|
// @ts-ignore
|
|
562
627
|
log$1.error({
|
|
563
|
-
errcode: err == null ? void 0 : err.code
|
|
564
|
-
|
|
628
|
+
errcode: err == null ? void 0 : err.code,
|
|
629
|
+
msg: err == null ? void 0 : err.message
|
|
630
|
+
}, 'request error');
|
|
565
631
|
// @ts-ignore
|
|
566
632
|
switch(err == null ? void 0 : err.code){
|
|
567
633
|
case 'ENOTFOUND':
|
|
@@ -576,6 +642,10 @@ let Request = class Request extends stream.Duplex {
|
|
|
576
642
|
case 'ECONNRESET':
|
|
577
643
|
m.emit('error', new ConnResetError());
|
|
578
644
|
break;
|
|
645
|
+
// [FIX] 捕获证书错误,给予更友好的提示(虽然修复后不应再出现此错误)
|
|
646
|
+
case 'DEPTH_ZERO_SELF_SIGNED_CERT':
|
|
647
|
+
m.emit('error', utils.createErrorType('ERR_TLS_CERT', `SSL证书错误(自签名): ${err.message}`));
|
|
648
|
+
break;
|
|
579
649
|
default:
|
|
580
650
|
m.emit('error', utils.createErrorType('ERR_CONNOTHER', `网络错误: ${err.message}`));
|
|
581
651
|
}
|
package/dist/request.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* wia request v3.0.
|
|
2
|
+
* wia request v3.0.39
|
|
3
3
|
* (c) 2022-2025 Sibyl Yu and contributors
|
|
4
4
|
* Released under the MIT License.
|
|
5
5
|
*/
|
|
@@ -522,24 +522,88 @@ let Request = class Request extends Duplex {
|
|
|
522
522
|
// agents 优于 agent
|
|
523
523
|
if (agents) {
|
|
524
524
|
const scheme = protocol.slice(0, -1);
|
|
525
|
-
opt.agent
|
|
525
|
+
// [FIX] 仅当 agents 中存在对应协议的 agent 时才覆盖 opt.agent
|
|
526
|
+
// 防止 agents['https'] 为空时将 opt.agent 覆盖为 undefined,导致回退到 globalAgent
|
|
527
|
+
if (agents[scheme]) opt.agent = agents[scheme];
|
|
526
528
|
// http 非隧道代理模式,模块以代理主机为准,其他以目的网址为准
|
|
527
529
|
// 代理内部会根据代理协议选择 http(s) 发起请求创建连接
|
|
528
530
|
if (protocol === 'http:' && agents.http) {
|
|
529
|
-
|
|
531
|
+
// 注意:这里修改的是局部变量 protocol,用于选择 httpModule
|
|
532
|
+
// protocol 以proxy协议为准
|
|
533
|
+
const { proxy } = agents.http;
|
|
534
|
+
if (proxy && !agents.http.tunnel) protocol = proxy.protocol;
|
|
530
535
|
}
|
|
531
536
|
// log({scheme, agents, protocol}, 'request')
|
|
532
537
|
}
|
|
533
538
|
const httpModule = httpModules[protocol];
|
|
534
539
|
if (!httpModule) throw TypeError(`Unsupported protocol: ${protocol}`);
|
|
535
|
-
//
|
|
536
|
-
//
|
|
537
|
-
//
|
|
540
|
+
// ============================================================
|
|
541
|
+
// [FIX] 针对 Bun 的终极修复:构建纯净的 Request Options
|
|
542
|
+
// ============================================================
|
|
543
|
+
// 1. 定义标准 Node.js http.request 接受的字段白名单
|
|
544
|
+
// 避免传入 agents, followRedirects 等杂质干扰 Bun 的解析
|
|
545
|
+
const nativeFields = [
|
|
546
|
+
'agent',
|
|
547
|
+
'auth',
|
|
548
|
+
'createConnection',
|
|
549
|
+
'defaultPort',
|
|
550
|
+
'family',
|
|
551
|
+
'headers',
|
|
552
|
+
'hints',
|
|
553
|
+
'host',
|
|
554
|
+
'hostname',
|
|
555
|
+
'insecureHTTPParser',
|
|
556
|
+
'localAddress',
|
|
557
|
+
'localPort',
|
|
558
|
+
'lookup',
|
|
559
|
+
'maxHeaderSize',
|
|
560
|
+
'method',
|
|
561
|
+
'path',
|
|
562
|
+
'port',
|
|
563
|
+
'protocol',
|
|
564
|
+
'rejectUnauthorized',
|
|
565
|
+
'servername',
|
|
566
|
+
'setHost',
|
|
567
|
+
'socketPath',
|
|
568
|
+
'timeout',
|
|
569
|
+
'signal'
|
|
570
|
+
];
|
|
571
|
+
// 2. 创建纯净的 options 对象
|
|
572
|
+
const reqOpt = {};
|
|
573
|
+
// 3. 显式拷贝字段 (同时也解决了 [Object: null prototype] 问题)
|
|
574
|
+
for (const field of nativeFields){
|
|
575
|
+
if (opt[field] !== undefined) reqOpt[field] = opt[field];
|
|
576
|
+
}
|
|
577
|
+
// 端口修正逻辑 (保持不变)
|
|
578
|
+
if (!reqOpt.port) reqOpt.port = protocol === 'https:' ? 443 : 80;
|
|
579
|
+
else if (reqOpt.port) reqOpt.port = Number(reqOpt.port);
|
|
580
|
+
// 再次显式确保 agent 存在于新对象中 (防御性编程)
|
|
581
|
+
// if (opt.agent) reqOpt.agent = opt.agent
|
|
582
|
+
// ============================================================
|
|
583
|
+
// [FIX] 针对 Bun 的强制代理修复
|
|
584
|
+
// ============================================================
|
|
585
|
+
if (opt.agent) {
|
|
586
|
+
// 1. 仍然赋值 agent,以便 Node.js 环境正常工作
|
|
587
|
+
reqOpt.agent = opt.agent;
|
|
588
|
+
// 2. 【关键】针对 Bun:直接将 Agent 的创建连接方法暴露给 Request
|
|
589
|
+
// Bun 的 http.request 可能忽略 agent 对象,但通常会尊重 createConnection 选项
|
|
590
|
+
reqOpt.createConnection = (args, cb)=>{
|
|
591
|
+
log$1({
|
|
592
|
+
args
|
|
593
|
+
}, 'Direct createConnection triggered via options');
|
|
594
|
+
// 强制调用你的 Agent 的 createConnection
|
|
595
|
+
// 注意:需要确保 this 上下文正确指向 opt.agent
|
|
596
|
+
return opt.agent.createConnection(args, cb);
|
|
597
|
+
};
|
|
598
|
+
}
|
|
538
599
|
log$1({
|
|
539
|
-
|
|
540
|
-
|
|
600
|
+
reqOpt,
|
|
601
|
+
protocol,
|
|
602
|
+
agentType: reqOpt.agent ? 'custom' : 'global'
|
|
541
603
|
}, 'request');
|
|
542
|
-
|
|
604
|
+
// Create the native request and set up its event handlers
|
|
605
|
+
// @ts-ignore
|
|
606
|
+
const req = httpModule.request(reqOpt, m._onResponse);
|
|
543
607
|
m._currentRequest = req;
|
|
544
608
|
// @ts-ignore
|
|
545
609
|
req.redirectReq = m;
|
|
@@ -548,7 +612,8 @@ let Request = class Request extends Duplex {
|
|
|
548
612
|
// set tcp keep alive to prevent drop connection by peer
|
|
549
613
|
req.on('socket', /** @param {*} socket */ (socket)=>{
|
|
550
614
|
// default interval of sending ack packet is 1 minute
|
|
551
|
-
socket
|
|
615
|
+
// [FIX] 增加 socket 存在性检查,防止极少数情况下的 race condition
|
|
616
|
+
if (socket) socket.setKeepAlive(true, 1000 * 60);
|
|
552
617
|
});
|
|
553
618
|
// 请求error单独处理
|
|
554
619
|
// 'error' 事件处理,避免错误将冒泡到全局导致程序崩溃
|
|
@@ -557,8 +622,9 @@ let Request = class Request extends Duplex {
|
|
|
557
622
|
;
|
|
558
623
|
// @ts-ignore
|
|
559
624
|
log$1.error({
|
|
560
|
-
errcode: err == null ? void 0 : err.code
|
|
561
|
-
|
|
625
|
+
errcode: err == null ? void 0 : err.code,
|
|
626
|
+
msg: err == null ? void 0 : err.message
|
|
627
|
+
}, 'request error');
|
|
562
628
|
// @ts-ignore
|
|
563
629
|
switch(err == null ? void 0 : err.code){
|
|
564
630
|
case 'ENOTFOUND':
|
|
@@ -573,6 +639,10 @@ let Request = class Request extends Duplex {
|
|
|
573
639
|
case 'ECONNRESET':
|
|
574
640
|
m.emit('error', new ConnResetError());
|
|
575
641
|
break;
|
|
642
|
+
// [FIX] 捕获证书错误,给予更友好的提示(虽然修复后不应再出现此错误)
|
|
643
|
+
case 'DEPTH_ZERO_SELF_SIGNED_CERT':
|
|
644
|
+
m.emit('error', utils.createErrorType('ERR_TLS_CERT', `SSL证书错误(自签名): ${err.message}`));
|
|
645
|
+
break;
|
|
576
646
|
default:
|
|
577
647
|
m.emit('error', utils.createErrorType('ERR_CONNOTHER', `网络错误: ${err.message}`));
|
|
578
648
|
}
|
package/lib/request.js
CHANGED
|
@@ -163,24 +163,88 @@ let Request = class Request extends Duplex {
|
|
|
163
163
|
// agents 优于 agent
|
|
164
164
|
if (agents) {
|
|
165
165
|
const scheme = protocol.slice(0, -1);
|
|
166
|
-
opt.agent
|
|
166
|
+
// [FIX] 仅当 agents 中存在对应协议的 agent 时才覆盖 opt.agent
|
|
167
|
+
// 防止 agents['https'] 为空时将 opt.agent 覆盖为 undefined,导致回退到 globalAgent
|
|
168
|
+
if (agents[scheme]) opt.agent = agents[scheme];
|
|
167
169
|
// http 非隧道代理模式,模块以代理主机为准,其他以目的网址为准
|
|
168
170
|
// 代理内部会根据代理协议选择 http(s) 发起请求创建连接
|
|
169
171
|
if (protocol === 'http:' && agents.http) {
|
|
170
|
-
|
|
172
|
+
// 注意:这里修改的是局部变量 protocol,用于选择 httpModule
|
|
173
|
+
// protocol 以proxy协议为准
|
|
174
|
+
const { proxy } = agents.http;
|
|
175
|
+
if (proxy && !agents.http.tunnel) protocol = proxy.protocol;
|
|
171
176
|
}
|
|
172
177
|
// log({scheme, agents, protocol}, 'request')
|
|
173
178
|
}
|
|
174
179
|
const httpModule = httpModules[protocol];
|
|
175
180
|
if (!httpModule) throw TypeError(`Unsupported protocol: ${protocol}`);
|
|
176
|
-
//
|
|
177
|
-
//
|
|
178
|
-
//
|
|
181
|
+
// ============================================================
|
|
182
|
+
// [FIX] 针对 Bun 的终极修复:构建纯净的 Request Options
|
|
183
|
+
// ============================================================
|
|
184
|
+
// 1. 定义标准 Node.js http.request 接受的字段白名单
|
|
185
|
+
// 避免传入 agents, followRedirects 等杂质干扰 Bun 的解析
|
|
186
|
+
const nativeFields = [
|
|
187
|
+
'agent',
|
|
188
|
+
'auth',
|
|
189
|
+
'createConnection',
|
|
190
|
+
'defaultPort',
|
|
191
|
+
'family',
|
|
192
|
+
'headers',
|
|
193
|
+
'hints',
|
|
194
|
+
'host',
|
|
195
|
+
'hostname',
|
|
196
|
+
'insecureHTTPParser',
|
|
197
|
+
'localAddress',
|
|
198
|
+
'localPort',
|
|
199
|
+
'lookup',
|
|
200
|
+
'maxHeaderSize',
|
|
201
|
+
'method',
|
|
202
|
+
'path',
|
|
203
|
+
'port',
|
|
204
|
+
'protocol',
|
|
205
|
+
'rejectUnauthorized',
|
|
206
|
+
'servername',
|
|
207
|
+
'setHost',
|
|
208
|
+
'socketPath',
|
|
209
|
+
'timeout',
|
|
210
|
+
'signal'
|
|
211
|
+
];
|
|
212
|
+
// 2. 创建纯净的 options 对象
|
|
213
|
+
const reqOpt = {};
|
|
214
|
+
// 3. 显式拷贝字段 (同时也解决了 [Object: null prototype] 问题)
|
|
215
|
+
for (const field of nativeFields){
|
|
216
|
+
if (opt[field] !== undefined) reqOpt[field] = opt[field];
|
|
217
|
+
}
|
|
218
|
+
// 端口修正逻辑 (保持不变)
|
|
219
|
+
if (!reqOpt.port) reqOpt.port = protocol === 'https:' ? 443 : 80;
|
|
220
|
+
else if (reqOpt.port) reqOpt.port = Number(reqOpt.port);
|
|
221
|
+
// 再次显式确保 agent 存在于新对象中 (防御性编程)
|
|
222
|
+
// if (opt.agent) reqOpt.agent = opt.agent
|
|
223
|
+
// ============================================================
|
|
224
|
+
// [FIX] 针对 Bun 的强制代理修复
|
|
225
|
+
// ============================================================
|
|
226
|
+
if (opt.agent) {
|
|
227
|
+
// 1. 仍然赋值 agent,以便 Node.js 环境正常工作
|
|
228
|
+
reqOpt.agent = opt.agent;
|
|
229
|
+
// 2. 【关键】针对 Bun:直接将 Agent 的创建连接方法暴露给 Request
|
|
230
|
+
// Bun 的 http.request 可能忽略 agent 对象,但通常会尊重 createConnection 选项
|
|
231
|
+
reqOpt.createConnection = (args, cb)=>{
|
|
232
|
+
log({
|
|
233
|
+
args
|
|
234
|
+
}, 'Direct createConnection triggered via options');
|
|
235
|
+
// 强制调用你的 Agent 的 createConnection
|
|
236
|
+
// 注意:需要确保 this 上下文正确指向 opt.agent
|
|
237
|
+
return opt.agent.createConnection(args, cb);
|
|
238
|
+
};
|
|
239
|
+
}
|
|
179
240
|
log({
|
|
180
|
-
|
|
181
|
-
|
|
241
|
+
reqOpt,
|
|
242
|
+
protocol,
|
|
243
|
+
agentType: reqOpt.agent ? 'custom' : 'global'
|
|
182
244
|
}, 'request');
|
|
183
|
-
|
|
245
|
+
// Create the native request and set up its event handlers
|
|
246
|
+
// @ts-ignore
|
|
247
|
+
const req = httpModule.request(reqOpt, m._onResponse);
|
|
184
248
|
m._currentRequest = req;
|
|
185
249
|
// @ts-ignore
|
|
186
250
|
req.redirectReq = m;
|
|
@@ -189,7 +253,8 @@ let Request = class Request extends Duplex {
|
|
|
189
253
|
// set tcp keep alive to prevent drop connection by peer
|
|
190
254
|
req.on('socket', /** @param {*} socket */ (socket)=>{
|
|
191
255
|
// default interval of sending ack packet is 1 minute
|
|
192
|
-
socket
|
|
256
|
+
// [FIX] 增加 socket 存在性检查,防止极少数情况下的 race condition
|
|
257
|
+
if (socket) socket.setKeepAlive(true, 1000 * 60);
|
|
193
258
|
});
|
|
194
259
|
// 请求error单独处理
|
|
195
260
|
// 'error' 事件处理,避免错误将冒泡到全局导致程序崩溃
|
|
@@ -198,8 +263,9 @@ let Request = class Request extends Duplex {
|
|
|
198
263
|
;
|
|
199
264
|
// @ts-ignore
|
|
200
265
|
log.error({
|
|
201
|
-
errcode: err == null ? void 0 : err.code
|
|
202
|
-
|
|
266
|
+
errcode: err == null ? void 0 : err.code,
|
|
267
|
+
msg: err == null ? void 0 : err.message
|
|
268
|
+
}, 'request error');
|
|
203
269
|
// @ts-ignore
|
|
204
270
|
switch(err == null ? void 0 : err.code){
|
|
205
271
|
case 'ENOTFOUND':
|
|
@@ -214,6 +280,10 @@ let Request = class Request extends Duplex {
|
|
|
214
280
|
case 'ECONNRESET':
|
|
215
281
|
m.emit('error', new ConnResetError());
|
|
216
282
|
break;
|
|
283
|
+
// [FIX] 捕获证书错误,给予更友好的提示(虽然修复后不应再出现此错误)
|
|
284
|
+
case 'DEPTH_ZERO_SELF_SIGNED_CERT':
|
|
285
|
+
m.emit('error', utils.createErrorType('ERR_TLS_CERT', `SSL证书错误(自签名): ${err.message}`));
|
|
286
|
+
break;
|
|
217
287
|
default:
|
|
218
288
|
m.emit('error', utils.createErrorType('ERR_CONNOTHER', `网络错误: ${err.message}`));
|
|
219
289
|
}
|
package/package.json
CHANGED