@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 CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * wia request v3.0.37
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 = agents[scheme];
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
- protocol = agents.http.proxy && !agents.http.tunnel ? agents.http.proxy.protocol : protocol;
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
- // log({opt, protocol}, 'request')
539
- // Create the native request and set up its event handlers
540
- // @ts-ignore
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
- httpModule,
543
- opt
603
+ reqOpt,
604
+ protocol,
605
+ agentType: reqOpt.agent ? 'custom' : 'global'
544
606
  }, 'request');
545
- const req = httpModule.request(opt, m._onResponse);
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.setKeepAlive(true, 1000 * 60);
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
- }, 'request');
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.37
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 = agents[scheme];
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
- protocol = agents.http.proxy && !agents.http.tunnel ? agents.http.proxy.protocol : protocol;
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
- // log({opt, protocol}, 'request')
536
- // Create the native request and set up its event handlers
537
- // @ts-ignore
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
- httpModule,
540
- opt
600
+ reqOpt,
601
+ protocol,
602
+ agentType: reqOpt.agent ? 'custom' : 'global'
541
603
  }, 'request');
542
- const req = httpModule.request(opt, m._onResponse);
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.setKeepAlive(true, 1000 * 60);
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
- }, 'request');
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 = agents[scheme];
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
- protocol = agents.http.proxy && !agents.http.tunnel ? agents.http.proxy.protocol : protocol;
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
- // log({opt, protocol}, 'request')
177
- // Create the native request and set up its event handlers
178
- // @ts-ignore
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
- httpModule,
181
- opt
241
+ reqOpt,
242
+ protocol,
243
+ agentType: reqOpt.agent ? 'custom' : 'global'
182
244
  }, 'request');
183
- const req = httpModule.request(opt, m._onResponse);
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.setKeepAlive(true, 1000 * 60);
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
- }, 'request');
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.37",
5
+ "version": "3.0.39",
6
6
  "type": "module",
7
7
  "main": "index.js",
8
8
  "types": "types/index.d.ts",