@wiajs/request 3.0.36 → 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 +85 -16
- package/dist/request.mjs +85 -16
- package/lib/request.js +82 -12
- package/package.json +2 -2
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
|
*/
|
|
@@ -11,7 +11,6 @@ const assert = require('assert');
|
|
|
11
11
|
const http = require('http');
|
|
12
12
|
const https = require('https');
|
|
13
13
|
const mime = require('mime-types');
|
|
14
|
-
const stream$1 = require('node:stream');
|
|
15
14
|
const url = require('url');
|
|
16
15
|
const zlib = require('zlib');
|
|
17
16
|
|
|
@@ -498,7 +497,7 @@ const HostNotfoundError = utils.createErrorType('ERR_HOSTNOTFOUND', 'DNS 解析
|
|
|
498
497
|
const ConnRefusedError = utils.createErrorType('ERR_CONNREFUSED', '连接被拒绝,目标服务器可能不可用');
|
|
499
498
|
const ConnTimedoutError = utils.createErrorType('ERR_CONNTIMEDOUT', '请求超时,请检查网络连接或服务器负载');
|
|
500
499
|
const ConnResetError = utils.createErrorType('ERR_CONNRESET', '连接被重置,可能是网络问题或服务器关闭了连接');
|
|
501
|
-
let Request = class Request extends stream
|
|
500
|
+
let Request = class Request extends stream.Duplex {
|
|
502
501
|
/**
|
|
503
502
|
* Executes the next native request (initial or redirect)
|
|
504
503
|
* @returns http(s) 实例
|
|
@@ -526,24 +525,88 @@ let Request = class Request extends stream$1.Duplex {
|
|
|
526
525
|
// agents 优于 agent
|
|
527
526
|
if (agents) {
|
|
528
527
|
const scheme = protocol.slice(0, -1);
|
|
529
|
-
opt.agent
|
|
528
|
+
// [FIX] 仅当 agents 中存在对应协议的 agent 时才覆盖 opt.agent
|
|
529
|
+
// 防止 agents['https'] 为空时将 opt.agent 覆盖为 undefined,导致回退到 globalAgent
|
|
530
|
+
if (agents[scheme]) opt.agent = agents[scheme];
|
|
530
531
|
// http 非隧道代理模式,模块以代理主机为准,其他以目的网址为准
|
|
531
532
|
// 代理内部会根据代理协议选择 http(s) 发起请求创建连接
|
|
532
533
|
if (protocol === 'http:' && agents.http) {
|
|
533
|
-
|
|
534
|
+
// 注意:这里修改的是局部变量 protocol,用于选择 httpModule
|
|
535
|
+
// protocol 以proxy协议为准
|
|
536
|
+
const { proxy } = agents.http;
|
|
537
|
+
if (proxy && !agents.http.tunnel) protocol = proxy.protocol;
|
|
534
538
|
}
|
|
535
539
|
// log({scheme, agents, protocol}, 'request')
|
|
536
540
|
}
|
|
537
541
|
const httpModule = httpModules[protocol];
|
|
538
542
|
if (!httpModule) throw TypeError(`Unsupported protocol: ${protocol}`);
|
|
539
|
-
//
|
|
540
|
-
//
|
|
541
|
-
//
|
|
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
|
+
}
|
|
542
602
|
log$1({
|
|
543
|
-
|
|
544
|
-
|
|
603
|
+
reqOpt,
|
|
604
|
+
protocol,
|
|
605
|
+
agentType: reqOpt.agent ? 'custom' : 'global'
|
|
545
606
|
}, 'request');
|
|
546
|
-
|
|
607
|
+
// Create the native request and set up its event handlers
|
|
608
|
+
// @ts-ignore
|
|
609
|
+
const req = httpModule.request(reqOpt, m._onResponse);
|
|
547
610
|
m._currentRequest = req;
|
|
548
611
|
// @ts-ignore
|
|
549
612
|
req.redirectReq = m;
|
|
@@ -552,7 +615,8 @@ let Request = class Request extends stream$1.Duplex {
|
|
|
552
615
|
// set tcp keep alive to prevent drop connection by peer
|
|
553
616
|
req.on('socket', /** @param {*} socket */ (socket)=>{
|
|
554
617
|
// default interval of sending ack packet is 1 minute
|
|
555
|
-
socket
|
|
618
|
+
// [FIX] 增加 socket 存在性检查,防止极少数情况下的 race condition
|
|
619
|
+
if (socket) socket.setKeepAlive(true, 1000 * 60);
|
|
556
620
|
});
|
|
557
621
|
// 请求error单独处理
|
|
558
622
|
// 'error' 事件处理,避免错误将冒泡到全局导致程序崩溃
|
|
@@ -561,8 +625,9 @@ let Request = class Request extends stream$1.Duplex {
|
|
|
561
625
|
;
|
|
562
626
|
// @ts-ignore
|
|
563
627
|
log$1.error({
|
|
564
|
-
errcode: err == null ? void 0 : err.code
|
|
565
|
-
|
|
628
|
+
errcode: err == null ? void 0 : err.code,
|
|
629
|
+
msg: err == null ? void 0 : err.message
|
|
630
|
+
}, 'request error');
|
|
566
631
|
// @ts-ignore
|
|
567
632
|
switch(err == null ? void 0 : err.code){
|
|
568
633
|
case 'ENOTFOUND':
|
|
@@ -577,6 +642,10 @@ let Request = class Request extends stream$1.Duplex {
|
|
|
577
642
|
case 'ECONNRESET':
|
|
578
643
|
m.emit('error', new ConnResetError());
|
|
579
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;
|
|
580
649
|
default:
|
|
581
650
|
m.emit('error', utils.createErrorType('ERR_CONNOTHER', `网络错误: ${err.message}`));
|
|
582
651
|
}
|
|
@@ -1052,7 +1121,7 @@ let Request = class Request extends stream$1.Duplex {
|
|
|
1052
1121
|
}
|
|
1053
1122
|
// 响应流,用于读
|
|
1054
1123
|
// @ts-ignore
|
|
1055
|
-
responseStream = streams.length > 1 ? stream
|
|
1124
|
+
responseStream = streams.length > 1 ? stream.pipeline(streams, utils.noop) : streams[0];
|
|
1056
1125
|
// 将内部 responseStream 可读流 映射到 redirectReq
|
|
1057
1126
|
// @ts-ignore
|
|
1058
1127
|
m.responseStream = responseStream;
|
|
@@ -1078,7 +1147,7 @@ let Request = class Request extends stream$1.Duplex {
|
|
|
1078
1147
|
}
|
|
1079
1148
|
// 可读流结束,触发 finished,方便上层清理
|
|
1080
1149
|
// A cleanup function which removes all registered listeners.
|
|
1081
|
-
const offListeners = stream
|
|
1150
|
+
const offListeners = stream.finished(responseStream, ()=>{
|
|
1082
1151
|
offListeners() // cleanup
|
|
1083
1152
|
;
|
|
1084
1153
|
this.emit('finished');
|
package/dist/request.mjs
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
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
|
*/
|
|
6
6
|
import { log as log$2, name } from '@wiajs/log';
|
|
7
|
-
import stream from 'stream';
|
|
7
|
+
import stream, { Duplex } from 'stream';
|
|
8
8
|
import assert from 'assert';
|
|
9
9
|
import http from 'http';
|
|
10
10
|
import https from 'https';
|
|
11
11
|
import mime from 'mime-types';
|
|
12
|
-
import stream$1, { Duplex } from 'node:stream';
|
|
13
12
|
import url from 'url';
|
|
14
13
|
import zlib from 'zlib';
|
|
15
14
|
|
|
@@ -523,24 +522,88 @@ let Request = class Request extends Duplex {
|
|
|
523
522
|
// agents 优于 agent
|
|
524
523
|
if (agents) {
|
|
525
524
|
const scheme = protocol.slice(0, -1);
|
|
526
|
-
opt.agent
|
|
525
|
+
// [FIX] 仅当 agents 中存在对应协议的 agent 时才覆盖 opt.agent
|
|
526
|
+
// 防止 agents['https'] 为空时将 opt.agent 覆盖为 undefined,导致回退到 globalAgent
|
|
527
|
+
if (agents[scheme]) opt.agent = agents[scheme];
|
|
527
528
|
// http 非隧道代理模式,模块以代理主机为准,其他以目的网址为准
|
|
528
529
|
// 代理内部会根据代理协议选择 http(s) 发起请求创建连接
|
|
529
530
|
if (protocol === 'http:' && agents.http) {
|
|
530
|
-
|
|
531
|
+
// 注意:这里修改的是局部变量 protocol,用于选择 httpModule
|
|
532
|
+
// protocol 以proxy协议为准
|
|
533
|
+
const { proxy } = agents.http;
|
|
534
|
+
if (proxy && !agents.http.tunnel) protocol = proxy.protocol;
|
|
531
535
|
}
|
|
532
536
|
// log({scheme, agents, protocol}, 'request')
|
|
533
537
|
}
|
|
534
538
|
const httpModule = httpModules[protocol];
|
|
535
539
|
if (!httpModule) throw TypeError(`Unsupported protocol: ${protocol}`);
|
|
536
|
-
//
|
|
537
|
-
//
|
|
538
|
-
//
|
|
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
|
+
}
|
|
539
599
|
log$1({
|
|
540
|
-
|
|
541
|
-
|
|
600
|
+
reqOpt,
|
|
601
|
+
protocol,
|
|
602
|
+
agentType: reqOpt.agent ? 'custom' : 'global'
|
|
542
603
|
}, 'request');
|
|
543
|
-
|
|
604
|
+
// Create the native request and set up its event handlers
|
|
605
|
+
// @ts-ignore
|
|
606
|
+
const req = httpModule.request(reqOpt, m._onResponse);
|
|
544
607
|
m._currentRequest = req;
|
|
545
608
|
// @ts-ignore
|
|
546
609
|
req.redirectReq = m;
|
|
@@ -549,7 +612,8 @@ let Request = class Request extends Duplex {
|
|
|
549
612
|
// set tcp keep alive to prevent drop connection by peer
|
|
550
613
|
req.on('socket', /** @param {*} socket */ (socket)=>{
|
|
551
614
|
// default interval of sending ack packet is 1 minute
|
|
552
|
-
socket
|
|
615
|
+
// [FIX] 增加 socket 存在性检查,防止极少数情况下的 race condition
|
|
616
|
+
if (socket) socket.setKeepAlive(true, 1000 * 60);
|
|
553
617
|
});
|
|
554
618
|
// 请求error单独处理
|
|
555
619
|
// 'error' 事件处理,避免错误将冒泡到全局导致程序崩溃
|
|
@@ -558,8 +622,9 @@ let Request = class Request extends Duplex {
|
|
|
558
622
|
;
|
|
559
623
|
// @ts-ignore
|
|
560
624
|
log$1.error({
|
|
561
|
-
errcode: err == null ? void 0 : err.code
|
|
562
|
-
|
|
625
|
+
errcode: err == null ? void 0 : err.code,
|
|
626
|
+
msg: err == null ? void 0 : err.message
|
|
627
|
+
}, 'request error');
|
|
563
628
|
// @ts-ignore
|
|
564
629
|
switch(err == null ? void 0 : err.code){
|
|
565
630
|
case 'ENOTFOUND':
|
|
@@ -574,6 +639,10 @@ let Request = class Request extends Duplex {
|
|
|
574
639
|
case 'ECONNRESET':
|
|
575
640
|
m.emit('error', new ConnResetError());
|
|
576
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;
|
|
577
646
|
default:
|
|
578
647
|
m.emit('error', utils.createErrorType('ERR_CONNOTHER', `网络错误: ${err.message}`));
|
|
579
648
|
}
|
|
@@ -1049,7 +1118,7 @@ let Request = class Request extends Duplex {
|
|
|
1049
1118
|
}
|
|
1050
1119
|
// 响应流,用于读
|
|
1051
1120
|
// @ts-ignore
|
|
1052
|
-
responseStream = streams.length > 1 ? stream
|
|
1121
|
+
responseStream = streams.length > 1 ? stream.pipeline(streams, utils.noop) : streams[0];
|
|
1053
1122
|
// 将内部 responseStream 可读流 映射到 redirectReq
|
|
1054
1123
|
// @ts-ignore
|
|
1055
1124
|
m.responseStream = responseStream;
|
|
@@ -1075,7 +1144,7 @@ let Request = class Request extends Duplex {
|
|
|
1075
1144
|
}
|
|
1076
1145
|
// 可读流结束,触发 finished,方便上层清理
|
|
1077
1146
|
// A cleanup function which removes all registered listeners.
|
|
1078
|
-
const offListeners = stream
|
|
1147
|
+
const offListeners = stream.finished(responseStream, ()=>{
|
|
1079
1148
|
offListeners() // cleanup
|
|
1080
1149
|
;
|
|
1081
1150
|
this.emit('finished');
|
package/lib/request.js
CHANGED
|
@@ -6,7 +6,7 @@ import assert from 'assert';
|
|
|
6
6
|
import http from 'http';
|
|
7
7
|
import https from 'https';
|
|
8
8
|
import mime from 'mime-types';
|
|
9
|
-
import stream, { Duplex } from '
|
|
9
|
+
import stream, { Duplex } from 'stream';
|
|
10
10
|
import url from 'url';
|
|
11
11
|
import zlib from 'zlib';
|
|
12
12
|
import ZlibTransform from './ZlibTransform.js';
|
|
@@ -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
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@wiajs/request",
|
|
3
3
|
"description": "Stream HTTP request client.",
|
|
4
4
|
"keywords": ["http", "simple", "util", "utility"],
|
|
5
|
-
"version": "3.0.
|
|
5
|
+
"version": "3.0.39",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "index.js",
|
|
8
8
|
"types": "types/index.d.ts",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"access": "public"
|
|
44
44
|
},
|
|
45
45
|
"engines": {
|
|
46
|
-
"node": ">=
|
|
46
|
+
"node": ">= 13.14"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"@wiajs/log": "^4.3.18",
|