@wiajs/request 3.0.20 → 3.0.23

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.19
2
+ * wia request v3.0.23
3
3
  * (c) 2022-2024 Sibyl Yu and contributors
4
4
  * Released under the MIT License.
5
5
  */
@@ -92,10 +92,10 @@ const preservedUrlFields = [
92
92
  * @property {string} message - The error message.
93
93
  * @property {Error | undefined} cause - The optional error cause.
94
94
  */
95
- function createErrorType(code, message, baseClass) {
95
+ function createErrorType(code, message, baseClass) {
96
96
  /**
97
97
  * Create constructor
98
- * @param {*} properties
98
+ * @param {*} properties
99
99
  */
100
100
  function CustomError(properties) {
101
101
  // istanbul ignore else
@@ -120,7 +120,7 @@ function createErrorType(code, message, baseClass) {
120
120
  enumerable: false,
121
121
  },
122
122
  });
123
-
123
+
124
124
  // @ts-ignore
125
125
  return CustomError
126
126
  }
@@ -221,9 +221,9 @@ function isURL(value) {
221
221
  }
222
222
 
223
223
  /**
224
- *
225
- * @param {*} rs
226
- * @returns
224
+ *
225
+ * @param {*} rs
226
+ * @returns
227
227
  */
228
228
  function isReadStream(rs) {
229
229
  return rs.readable && rs.path && rs.mode
@@ -319,6 +319,15 @@ function noBody(method, code) {
319
319
  )
320
320
  }
321
321
 
322
+ /**
323
+ * Determine if a value is a Stream
324
+ *
325
+ * @param {*} val The value to test
326
+ *
327
+ * @returns {boolean} True if value is a Stream, otherwise false
328
+ */
329
+ const isStream = val => isObject(val) && isFunction(val.pipe);
330
+
322
331
  const utils = {
323
332
  createErrorType,
324
333
  InvalidUrlError,
@@ -332,6 +341,7 @@ const utils = {
332
341
  isObject,
333
342
  isURL,
334
343
  isReadStream,
344
+ isStream,
335
345
  noop,
336
346
  parseUrl,
337
347
  spreadUrlObject,
@@ -439,7 +449,7 @@ class Caseless {
439
449
  * https://github.com/follow-redirects/follow-redirects
440
450
  */
441
451
 
442
- const log$1 = log$2.log({env: `wia:req:${log$2.name((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.src || new URL('request.cjs', document.baseURI).href)))}`}); // __filename
452
+ const log$1 = log$2.log({env: `wia:req:${log$2.name((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('request.cjs', document.baseURI).href)))}`}); // __filename
443
453
 
444
454
  /**
445
455
  * @typedef {object} Opts
@@ -509,7 +519,7 @@ const writeProps = [
509
519
  const writeMethods = ['cork', 'flushHeaders', 'setNoDelay', 'setSocketKeepAlive'];
510
520
 
511
521
  // Create handlers that pass events from native requests
512
- // 在 clientRequest 事件转发
522
+ // 在 clientRequest 事件转发写事件
513
523
  const writeEvents = [
514
524
  // 'abort', // 弃用
515
525
  // 'aborted', // 弃用
@@ -533,7 +543,7 @@ const writeEventEmit = Object.create(null);
533
543
  for (const ev of writeEvents)
534
544
  writeEventEmit[ev] = /** @param {...any} args */ function (...args) {
535
545
  const m = this; // 事件回调,this === clientRequest 实例
536
- log$1('req event', {ev});
546
+ // log('req event', {ev})
537
547
  m.redirectReq.emit(ev, ...args); // req 事情映射到 redirectReq 上触发
538
548
  };
539
549
 
@@ -544,7 +554,7 @@ const readEventEmit = Object.create(null);
544
554
  for (const ev of readEvents)
545
555
  readEventEmit[ev] = /** @param {...any} args */ function (...args) {
546
556
  const m = this; // 事件回调,this === clientRequest 实例
547
- log$1('res event', {ev});
557
+ // log('res event', {ev})
548
558
  m.redirectReq.emit(ev, ...args); // 向上触发事件
549
559
  };
550
560
 
@@ -664,14 +674,14 @@ class Request extends stream.Duplex {
664
674
  get() {
665
675
  // @ts-ignore
666
676
  const val = m._currentRequest?.[property];
667
- log$1('get property', {property});
677
+ // log('get property', {property})
668
678
  return val
669
679
  },
670
680
  });
671
681
  }
672
682
 
683
+ // 流模式
673
684
  if (opts.stream) {
674
- // 流模式
675
685
  // 被 pipe 作为目标时触发,拷贝 src headers
676
686
  m.on(
677
687
  'pipe',
@@ -707,7 +717,7 @@ class Request extends stream.Duplex {
707
717
  }
708
718
 
709
719
  // Perform the first request
710
- // m.request(); // 写入数据时执行,否则 pipe 时无法写入header
720
+ // m.request(); // 创建时不连接,写入数据时连接,否则 pipe 时无法写入header
711
721
  }
712
722
 
713
723
  /**
@@ -739,6 +749,7 @@ class Request extends stream.Duplex {
739
749
  // 代理以目的网址协议为准
740
750
  // If specified, use the agent corresponding to the protocol
741
751
  // (HTTP and HTTPS use different types of agents)
752
+ // agents 优于 agent
742
753
  if (agents) {
743
754
  const scheme = protocol.slice(0, -1);
744
755
  opt.agent = agents[scheme];
@@ -842,13 +853,13 @@ class Request extends stream.Duplex {
842
853
  * 如 request 不存在,则创建连接,pipe 时可写入 header
843
854
  * @override - 重写父类方法
844
855
  * @param {*} chunk - The data chunk to write.
845
- * @param {BufferEncoding | ((error: Error | null) => void)} [encodingOrCallback] - Encoding for string data, or the callback if no encoding is provided.
856
+ * @param {BufferEncoding | ((error: Error | null) => void)} [encoding] - Encoding for string data, or the callback if no encoding is provided.
846
857
  * @param {(error: Error | null) => void} [cb] - Callback to signal the end of the write operation.
847
858
  * @returns {boolean} True if the write was successful, false otherwise.
848
859
  */
849
- write(chunk, encodingOrCallback, cb) {
860
+ write(chunk, encoding, cb) {
850
861
  const m = this;
851
- log$1({data: chunk, encoding: encodingOrCallback, callback: cb}, 'write');
862
+ // log({data: chunk, encoding, cb}, 'write')
852
863
 
853
864
  // Writing is not allowed if end has been called
854
865
  if (m._ending) throw new WriteAfterEndError()
@@ -860,10 +871,10 @@ class Request extends stream.Duplex {
860
871
  if (!utils.isString(chunk) && !utils.isBuffer(chunk))
861
872
  throw new TypeError('data should be a string, Buffer or Uint8Array')
862
873
 
863
- if (utils.isFunction(encodingOrCallback)) {
874
+ if (utils.isFunction(encoding)) {
864
875
  // @ts-ignore
865
- cb = encodingOrCallback;
866
- encodingOrCallback = null;
876
+ cb = encoding;
877
+ encoding = null;
867
878
  }
868
879
 
869
880
  // Ignore empty buffers, since writing them doesn't invoke the callback
@@ -876,9 +887,9 @@ class Request extends stream.Duplex {
876
887
  // Only write when we don't exceed the maximum body length
877
888
  if (m._requestBodyLength + chunk.length <= m.opt.maxBodyLength) {
878
889
  m._requestBodyLength += chunk.length;
879
- m._requestBodyBuffers.push({data: chunk, encoding: encodingOrCallback});
890
+ m._requestBodyBuffers.push({data: chunk, encoding});
880
891
  // @ts-ignore
881
- m._currentRequest.write(chunk, encodingOrCallback, cb);
892
+ m._currentRequest.write(chunk, encoding, cb);
882
893
  }
883
894
  // Error when we exceed the maximum body length
884
895
  else {
@@ -909,7 +920,7 @@ class Request extends stream.Duplex {
909
920
  encoding = null;
910
921
  }
911
922
 
912
- // ! 数据写入时连接,pipe 时可设置 header
923
+ // ! 创建实例时不连接,数据写入时发起连接,连接后无法设置 header,因此 pipe 时可设置 header
913
924
  if (!m._currentRequest) m.request();
914
925
 
915
926
  // Write data if needed and end
@@ -1109,7 +1120,7 @@ class Request extends stream.Duplex {
1109
1120
  // If the response is not a redirect; return it as-is
1110
1121
  const {location} = response.headers;
1111
1122
 
1112
- log$1({statusCode, headers: response.headers}, 'processResponse');
1123
+ // log({statusCode, headers: response.headers}, 'processResponse')
1113
1124
 
1114
1125
  if (!location || opt.followRedirects === false || statusCode < 300 || statusCode >= 400) {
1115
1126
  // 非重定向,返回给原始回调处理
@@ -1245,11 +1256,11 @@ class Request extends stream.Duplex {
1245
1256
  // 'transfer-encoding': 'chunked'时,无content-length,axios v1.2 不能自动解压
1246
1257
  const responseLength = +res.headers['content-length'];
1247
1258
 
1248
- log$1('processStream', {
1249
- statusCode: res.statusCode,
1250
- responseLength,
1251
- headers: res.headers,
1252
- });
1259
+ // log('processStream', {
1260
+ // statusCode: res.statusCode,
1261
+ // responseLength,
1262
+ // headers: res.headers,
1263
+ // })
1253
1264
 
1254
1265
  if (opt.transformStream) {
1255
1266
  opt.transformStream.responseLength = responseLength;
@@ -1521,12 +1532,18 @@ function isSubdomain(subdomain, domain) {
1521
1532
 
1522
1533
  /**
1523
1534
  * from 'https://github.com/follow-redirects/follow-redirects'
1535
+ * used by axios
1524
1536
  * 修改以支持http、https 代理服务器
1525
1537
  * 代理模式下,http or https 请求,取决于 proxy 代理服务器,而不是目的服务器。
1526
1538
  */
1527
1539
 
1528
1540
 
1529
- const log = log$2.log({env: `wia:req:${log$2.name((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.src || new URL('request.cjs', document.baseURI).href)))}`}) // __filename
1541
+ const log = log$2.log({env: `wia:req:${log$2.name((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('request.cjs', document.baseURI).href)))}`}); // __filename
1542
+
1543
+ const WritebBeenAbortedError = utils.createErrorType(
1544
+ 'ERR_STREAM_WRITE_BEEN_ABORTED',
1545
+ 'Request stream has been aborted'
1546
+ )
1530
1547
 
1531
1548
  // Preventive platform detection
1532
1549
  // istanbul ignore
@@ -1589,6 +1606,7 @@ function init(uri, options, callback) {
1589
1606
  /**
1590
1607
  * Executes a request, following redirects
1591
1608
  * 替换原 http(s).request,参数类似
1609
+ * 需外部调用 end() data.pipe 或stream管道写入数据
1592
1610
  * 注意变参 (options[, callback]) or (url[, options][, callback])
1593
1611
  maxRedirects: _.maxRedirects,
1594
1612
  maxBodyLength: _.maxBodyLength,
@@ -1612,7 +1630,8 @@ function request(uri, options, callback) {
1612
1630
  }
1613
1631
 
1614
1632
  /**
1615
- * 执行简单的非stream数据请求
1633
+ * 执行简单的数据(支持strean)请求
1634
+ * 非流模式,直接写入数据流,流模式,由管道触发,或手动调用 end() data.pipe 写入数据
1616
1635
  * 复杂数据,请使用 @wiajs/req库(fork from axios),该库封装了当前库,提供了更多功能
1617
1636
  * organize params for patch, post, put, head, del
1618
1637
  * @param {string} verb
@@ -1626,7 +1645,35 @@ function fn(verb) {
1626
1645
  const {opts, cb} = init(uri, options, callback);
1627
1646
  opts.method = method;
1628
1647
  const req = new Request(opts, cb);
1629
- req.end();
1648
+ const {data, stream} = opts;
1649
+ if (!stream) {
1650
+ // 发送数据
1651
+ if (utils.isStream(data)) {
1652
+ // Send the request
1653
+ let ended = false;
1654
+ let errored = false;
1655
+
1656
+ data.on('end', () => {
1657
+ ended = true;
1658
+ });
1659
+
1660
+ data.once(
1661
+ 'error',
1662
+ /** @param {*} err */ err => {
1663
+ errored = true;
1664
+ req.destroy(err);
1665
+ }
1666
+ );
1667
+
1668
+ data.on('close', () => {
1669
+ if (!ended && !errored) {
1670
+ throw new WritebBeenAbortedError()
1671
+ }
1672
+ });
1673
+
1674
+ data.pipe(req); // 写入数据流
1675
+ } else req.end(data);
1676
+ }
1630
1677
  return req
1631
1678
  }
1632
1679
  }
@@ -1639,6 +1686,6 @@ request.post = fn('post');
1639
1686
  request.put = fn('put');
1640
1687
  request.patch = fn('patch');
1641
1688
  request.del = fn('delete');
1642
- request['delete'] = fn('delete');
1689
+ request.delete = fn('delete');
1643
1690
 
1644
1691
  module.exports = request;
package/dist/request.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * wia request v3.0.19
2
+ * wia request v3.0.23
3
3
  * (c) 2022-2024 Sibyl Yu and contributors
4
4
  * Released under the MIT License.
5
5
  */
@@ -89,10 +89,10 @@ const preservedUrlFields = [
89
89
  * @property {string} message - The error message.
90
90
  * @property {Error | undefined} cause - The optional error cause.
91
91
  */
92
- function createErrorType(code, message, baseClass) {
92
+ function createErrorType(code, message, baseClass) {
93
93
  /**
94
94
  * Create constructor
95
- * @param {*} properties
95
+ * @param {*} properties
96
96
  */
97
97
  function CustomError(properties) {
98
98
  // istanbul ignore else
@@ -117,7 +117,7 @@ function createErrorType(code, message, baseClass) {
117
117
  enumerable: false,
118
118
  },
119
119
  });
120
-
120
+
121
121
  // @ts-ignore
122
122
  return CustomError
123
123
  }
@@ -218,9 +218,9 @@ function isURL(value) {
218
218
  }
219
219
 
220
220
  /**
221
- *
222
- * @param {*} rs
223
- * @returns
221
+ *
222
+ * @param {*} rs
223
+ * @returns
224
224
  */
225
225
  function isReadStream(rs) {
226
226
  return rs.readable && rs.path && rs.mode
@@ -316,6 +316,15 @@ function noBody(method, code) {
316
316
  )
317
317
  }
318
318
 
319
+ /**
320
+ * Determine if a value is a Stream
321
+ *
322
+ * @param {*} val The value to test
323
+ *
324
+ * @returns {boolean} True if value is a Stream, otherwise false
325
+ */
326
+ const isStream = val => isObject(val) && isFunction(val.pipe);
327
+
319
328
  const utils = {
320
329
  createErrorType,
321
330
  InvalidUrlError,
@@ -329,6 +338,7 @@ const utils = {
329
338
  isObject,
330
339
  isURL,
331
340
  isReadStream,
341
+ isStream,
332
342
  noop,
333
343
  parseUrl,
334
344
  spreadUrlObject,
@@ -506,7 +516,7 @@ const writeProps = [
506
516
  const writeMethods = ['cork', 'flushHeaders', 'setNoDelay', 'setSocketKeepAlive'];
507
517
 
508
518
  // Create handlers that pass events from native requests
509
- // 在 clientRequest 事件转发
519
+ // 在 clientRequest 事件转发写事件
510
520
  const writeEvents = [
511
521
  // 'abort', // 弃用
512
522
  // 'aborted', // 弃用
@@ -530,7 +540,7 @@ const writeEventEmit = Object.create(null);
530
540
  for (const ev of writeEvents)
531
541
  writeEventEmit[ev] = /** @param {...any} args */ function (...args) {
532
542
  const m = this; // 事件回调,this === clientRequest 实例
533
- log$1('req event', {ev});
543
+ // log('req event', {ev})
534
544
  m.redirectReq.emit(ev, ...args); // req 事情映射到 redirectReq 上触发
535
545
  };
536
546
 
@@ -541,7 +551,7 @@ const readEventEmit = Object.create(null);
541
551
  for (const ev of readEvents)
542
552
  readEventEmit[ev] = /** @param {...any} args */ function (...args) {
543
553
  const m = this; // 事件回调,this === clientRequest 实例
544
- log$1('res event', {ev});
554
+ // log('res event', {ev})
545
555
  m.redirectReq.emit(ev, ...args); // 向上触发事件
546
556
  };
547
557
 
@@ -661,14 +671,14 @@ class Request extends Duplex {
661
671
  get() {
662
672
  // @ts-ignore
663
673
  const val = m._currentRequest?.[property];
664
- log$1('get property', {property});
674
+ // log('get property', {property})
665
675
  return val
666
676
  },
667
677
  });
668
678
  }
669
679
 
680
+ // 流模式
670
681
  if (opts.stream) {
671
- // 流模式
672
682
  // 被 pipe 作为目标时触发,拷贝 src headers
673
683
  m.on(
674
684
  'pipe',
@@ -704,7 +714,7 @@ class Request extends Duplex {
704
714
  }
705
715
 
706
716
  // Perform the first request
707
- // m.request(); // 写入数据时执行,否则 pipe 时无法写入header
717
+ // m.request(); // 创建时不连接,写入数据时连接,否则 pipe 时无法写入header
708
718
  }
709
719
 
710
720
  /**
@@ -736,6 +746,7 @@ class Request extends Duplex {
736
746
  // 代理以目的网址协议为准
737
747
  // If specified, use the agent corresponding to the protocol
738
748
  // (HTTP and HTTPS use different types of agents)
749
+ // agents 优于 agent
739
750
  if (agents) {
740
751
  const scheme = protocol.slice(0, -1);
741
752
  opt.agent = agents[scheme];
@@ -839,13 +850,13 @@ class Request extends Duplex {
839
850
  * 如 request 不存在,则创建连接,pipe 时可写入 header
840
851
  * @override - 重写父类方法
841
852
  * @param {*} chunk - The data chunk to write.
842
- * @param {BufferEncoding | ((error: Error | null) => void)} [encodingOrCallback] - Encoding for string data, or the callback if no encoding is provided.
853
+ * @param {BufferEncoding | ((error: Error | null) => void)} [encoding] - Encoding for string data, or the callback if no encoding is provided.
843
854
  * @param {(error: Error | null) => void} [cb] - Callback to signal the end of the write operation.
844
855
  * @returns {boolean} True if the write was successful, false otherwise.
845
856
  */
846
- write(chunk, encodingOrCallback, cb) {
857
+ write(chunk, encoding, cb) {
847
858
  const m = this;
848
- log$1({data: chunk, encoding: encodingOrCallback, callback: cb}, 'write');
859
+ // log({data: chunk, encoding, cb}, 'write')
849
860
 
850
861
  // Writing is not allowed if end has been called
851
862
  if (m._ending) throw new WriteAfterEndError()
@@ -857,10 +868,10 @@ class Request extends Duplex {
857
868
  if (!utils.isString(chunk) && !utils.isBuffer(chunk))
858
869
  throw new TypeError('data should be a string, Buffer or Uint8Array')
859
870
 
860
- if (utils.isFunction(encodingOrCallback)) {
871
+ if (utils.isFunction(encoding)) {
861
872
  // @ts-ignore
862
- cb = encodingOrCallback;
863
- encodingOrCallback = null;
873
+ cb = encoding;
874
+ encoding = null;
864
875
  }
865
876
 
866
877
  // Ignore empty buffers, since writing them doesn't invoke the callback
@@ -873,9 +884,9 @@ class Request extends Duplex {
873
884
  // Only write when we don't exceed the maximum body length
874
885
  if (m._requestBodyLength + chunk.length <= m.opt.maxBodyLength) {
875
886
  m._requestBodyLength += chunk.length;
876
- m._requestBodyBuffers.push({data: chunk, encoding: encodingOrCallback});
887
+ m._requestBodyBuffers.push({data: chunk, encoding});
877
888
  // @ts-ignore
878
- m._currentRequest.write(chunk, encodingOrCallback, cb);
889
+ m._currentRequest.write(chunk, encoding, cb);
879
890
  }
880
891
  // Error when we exceed the maximum body length
881
892
  else {
@@ -906,7 +917,7 @@ class Request extends Duplex {
906
917
  encoding = null;
907
918
  }
908
919
 
909
- // ! 数据写入时连接,pipe 时可设置 header
920
+ // ! 创建实例时不连接,数据写入时发起连接,连接后无法设置 header,因此 pipe 时可设置 header
910
921
  if (!m._currentRequest) m.request();
911
922
 
912
923
  // Write data if needed and end
@@ -1106,7 +1117,7 @@ class Request extends Duplex {
1106
1117
  // If the response is not a redirect; return it as-is
1107
1118
  const {location} = response.headers;
1108
1119
 
1109
- log$1({statusCode, headers: response.headers}, 'processResponse');
1120
+ // log({statusCode, headers: response.headers}, 'processResponse')
1110
1121
 
1111
1122
  if (!location || opt.followRedirects === false || statusCode < 300 || statusCode >= 400) {
1112
1123
  // 非重定向,返回给原始回调处理
@@ -1242,11 +1253,11 @@ class Request extends Duplex {
1242
1253
  // 'transfer-encoding': 'chunked'时,无content-length,axios v1.2 不能自动解压
1243
1254
  const responseLength = +res.headers['content-length'];
1244
1255
 
1245
- log$1('processStream', {
1246
- statusCode: res.statusCode,
1247
- responseLength,
1248
- headers: res.headers,
1249
- });
1256
+ // log('processStream', {
1257
+ // statusCode: res.statusCode,
1258
+ // responseLength,
1259
+ // headers: res.headers,
1260
+ // })
1250
1261
 
1251
1262
  if (opt.transformStream) {
1252
1263
  opt.transformStream.responseLength = responseLength;
@@ -1518,12 +1529,18 @@ function isSubdomain(subdomain, domain) {
1518
1529
 
1519
1530
  /**
1520
1531
  * from 'https://github.com/follow-redirects/follow-redirects'
1532
+ * used by axios
1521
1533
  * 修改以支持http、https 代理服务器
1522
1534
  * 代理模式下,http or https 请求,取决于 proxy 代理服务器,而不是目的服务器。
1523
1535
  */
1524
1536
 
1525
1537
 
1526
- const log = log$2({env: `wia:req:${name(import.meta.url)}`}) // __filename
1538
+ const log = log$2({env: `wia:req:${name(import.meta.url)}`}); // __filename
1539
+
1540
+ const WritebBeenAbortedError = utils.createErrorType(
1541
+ 'ERR_STREAM_WRITE_BEEN_ABORTED',
1542
+ 'Request stream has been aborted'
1543
+ )
1527
1544
 
1528
1545
  // Preventive platform detection
1529
1546
  // istanbul ignore
@@ -1586,6 +1603,7 @@ function init(uri, options, callback) {
1586
1603
  /**
1587
1604
  * Executes a request, following redirects
1588
1605
  * 替换原 http(s).request,参数类似
1606
+ * 需外部调用 end() data.pipe 或stream管道写入数据
1589
1607
  * 注意变参 (options[, callback]) or (url[, options][, callback])
1590
1608
  maxRedirects: _.maxRedirects,
1591
1609
  maxBodyLength: _.maxBodyLength,
@@ -1609,7 +1627,8 @@ function request(uri, options, callback) {
1609
1627
  }
1610
1628
 
1611
1629
  /**
1612
- * 执行简单的非stream数据请求
1630
+ * 执行简单的数据(支持strean)请求
1631
+ * 非流模式,直接写入数据流,流模式,由管道触发,或手动调用 end() data.pipe 写入数据
1613
1632
  * 复杂数据,请使用 @wiajs/req库(fork from axios),该库封装了当前库,提供了更多功能
1614
1633
  * organize params for patch, post, put, head, del
1615
1634
  * @param {string} verb
@@ -1623,7 +1642,35 @@ function fn(verb) {
1623
1642
  const {opts, cb} = init(uri, options, callback);
1624
1643
  opts.method = method;
1625
1644
  const req = new Request(opts, cb);
1626
- req.end();
1645
+ const {data, stream} = opts;
1646
+ if (!stream) {
1647
+ // 发送数据
1648
+ if (utils.isStream(data)) {
1649
+ // Send the request
1650
+ let ended = false;
1651
+ let errored = false;
1652
+
1653
+ data.on('end', () => {
1654
+ ended = true;
1655
+ });
1656
+
1657
+ data.once(
1658
+ 'error',
1659
+ /** @param {*} err */ err => {
1660
+ errored = true;
1661
+ req.destroy(err);
1662
+ }
1663
+ );
1664
+
1665
+ data.on('close', () => {
1666
+ if (!ended && !errored) {
1667
+ throw new WritebBeenAbortedError()
1668
+ }
1669
+ });
1670
+
1671
+ data.pipe(req); // 写入数据流
1672
+ } else req.end(data);
1673
+ }
1627
1674
  return req
1628
1675
  }
1629
1676
  }
@@ -1636,6 +1683,6 @@ request.post = fn('post');
1636
1683
  request.put = fn('put');
1637
1684
  request.patch = fn('patch');
1638
1685
  request.del = fn('delete');
1639
- request['delete'] = fn('delete');
1686
+ request.delete = fn('delete');
1640
1687
 
1641
1688
  export { request as default };
package/lib/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  /**
2
2
  * from 'https://github.com/follow-redirects/follow-redirects'
3
+ * used by axios
3
4
  * 修改以支持http、https 代理服务器
4
5
  * 代理模式下,http or https 请求,取决于 proxy 代理服务器,而不是目的服务器。
5
6
  */ import { log as Log, name } from '@wiajs/log';
@@ -9,6 +10,7 @@ const log = Log({
9
10
  env: `wia:req:${name(import.meta.url)}`
10
11
  }) // __filename
11
12
  ;
13
+ const WritebBeenAbortedError = utils.createErrorType('ERR_STREAM_WRITE_BEEN_ABORTED', 'Request stream has been aborted');
12
14
  (function detectUnsupportedEnvironment() {
13
15
  const looksLikeNode = typeof process !== 'undefined';
14
16
  const looksLikeBrowser = typeof window !== 'undefined' && typeof document !== 'undefined';
@@ -61,6 +63,7 @@ const log = Log({
61
63
  /**
62
64
  * Executes a request, following redirects
63
65
  * 替换原 http(s).request,参数类似
66
+ * 需外部调用 end() data.pipe 或stream管道写入数据
64
67
  * 注意变参 (options[, callback]) or (url[, options][, callback])
65
68
  maxRedirects: _.maxRedirects,
66
69
  maxBodyLength: _.maxBodyLength,
@@ -80,7 +83,8 @@ const log = Log({
80
83
  return R;
81
84
  }
82
85
  /**
83
- * 执行简单的非stream数据请求
86
+ * 执行简单的数据(支持strean)请求
87
+ * 非流模式,直接写入数据流,流模式,由管道触发,或手动调用 end() data.pipe 写入数据
84
88
  * 复杂数据,请使用 @wiajs/req库(fork from axios),该库封装了当前库,提供了更多功能
85
89
  * organize params for patch, post, put, head, del
86
90
  * @param {string} verb
@@ -92,7 +96,29 @@ const log = Log({
92
96
  const { opts, cb } = init(uri, options, callback);
93
97
  opts.method = method;
94
98
  const req = new Request(opts, cb);
95
- req.end();
99
+ const { data, stream } = opts;
100
+ if (!stream) {
101
+ // 发送数据
102
+ if (utils.isStream(data)) {
103
+ // Send the request
104
+ let ended = false;
105
+ let errored = false;
106
+ data.on('end', ()=>{
107
+ ended = true;
108
+ });
109
+ data.once('error', /** @param {*} err */ (err)=>{
110
+ errored = true;
111
+ req.destroy(err);
112
+ });
113
+ data.on('close', ()=>{
114
+ if (!ended && !errored) {
115
+ throw new WritebBeenAbortedError();
116
+ }
117
+ });
118
+ data.pipe(req) // 写入数据流
119
+ ;
120
+ } else req.end(data);
121
+ }
96
122
  return req;
97
123
  };
98
124
  }
@@ -104,5 +130,5 @@ request.post = fn('post');
104
130
  request.put = fn('put');
105
131
  request.patch = fn('patch');
106
132
  request.del = fn('delete');
107
- request['delete'] = fn('delete');
133
+ request.delete = fn('delete');
108
134
  export default request;
package/lib/request.js CHANGED
@@ -81,7 +81,7 @@ const writeMethods = [
81
81
  'setSocketKeepAlive'
82
82
  ];
83
83
  // Create handlers that pass events from native requests
84
- // 在 clientRequest 事件转发
84
+ // 在 clientRequest 事件转发写事件
85
85
  const writeEvents = [
86
86
  // 'abort', // 弃用
87
87
  // 'aborted', // 弃用
@@ -103,9 +103,7 @@ const writeEventEmit = Object.create(null);
103
103
  for (const ev of writeEvents)writeEventEmit[ev] = /** @param {...any} args */ function(...args) {
104
104
  const m = this // 事件回调,this === clientRequest 实例
105
105
  ;
106
- log('req event', {
107
- ev
108
- });
106
+ // log('req event', {ev})
109
107
  m.redirectReq.emit(ev, ...args) // req 事情映射到 redirectReq 上触发
110
108
  ;
111
109
  };
@@ -123,9 +121,7 @@ const readEventEmit = Object.create(null);
123
121
  for (const ev of readEvents)readEventEmit[ev] = /** @param {...any} args */ function(...args) {
124
122
  const m = this // 事件回调,this === clientRequest 实例
125
123
  ;
126
- log('res event', {
127
- ev
128
- });
124
+ // log('res event', {ev})
129
125
  m.redirectReq.emit(ev, ...args) // 向上触发事件
130
126
  ;
131
127
  };
@@ -193,15 +189,13 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
193
189
  get () {
194
190
  // @ts-ignore
195
191
  const val = m._currentRequest?.[property];
196
- log('get property', {
197
- property
198
- });
192
+ // log('get property', {property})
199
193
  return val;
200
194
  }
201
195
  });
202
196
  }
197
+ // 流模式
203
198
  if (opts.stream) {
204
- // 流模式
205
199
  // 被 pipe 作为目标时触发,拷贝 src headers
206
200
  m.on('pipe', /** @param {stream.Readable & {headers?: Object.<string, string>}} src */ (src)=>{
207
201
  // m.ntick &&
@@ -227,7 +221,7 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
227
221
  });
228
222
  }
229
223
  // Perform the first request
230
- // m.request(); // 写入数据时执行,否则 pipe 时无法写入header
224
+ // m.request(); // 创建时不连接,写入数据时连接,否则 pipe 时无法写入header
231
225
  }
232
226
  /**
233
227
  * Executes the next native request (initial or redirect)
@@ -253,6 +247,7 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
253
247
  // 代理以目的网址协议为准
254
248
  // If specified, use the agent corresponding to the protocol
255
249
  // (HTTP and HTTPS use different types of agents)
250
+ // agents 优于 agent
256
251
  if (agents) {
257
252
  const scheme = protocol.slice(0, -1);
258
253
  opt.agent = agents[scheme];
@@ -336,26 +331,22 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
336
331
  * 如 request 不存在,则创建连接,pipe 时可写入 header
337
332
  * @override - 重写父类方法
338
333
  * @param {*} chunk - The data chunk to write.
339
- * @param {BufferEncoding | ((error: Error | null) => void)} [encodingOrCallback] - Encoding for string data, or the callback if no encoding is provided.
334
+ * @param {BufferEncoding | ((error: Error | null) => void)} [encoding] - Encoding for string data, or the callback if no encoding is provided.
340
335
  * @param {(error: Error | null) => void} [cb] - Callback to signal the end of the write operation.
341
336
  * @returns {boolean} True if the write was successful, false otherwise.
342
- */ write(chunk, encodingOrCallback, cb) {
337
+ */ write(chunk, encoding, cb) {
343
338
  const m = this;
344
- log({
345
- data: chunk,
346
- encoding: encodingOrCallback,
347
- callback: cb
348
- }, 'write');
339
+ // log({data: chunk, encoding, cb}, 'write')
349
340
  // Writing is not allowed if end has been called
350
341
  if (m._ending) throw new WriteAfterEndError();
351
342
  // ! 数据写入时连接,pipe 时可设置 header
352
343
  if (!m._currentRequest) m.request();
353
344
  // Validate input and shift parameters if necessary
354
345
  if (!utils.isString(chunk) && !utils.isBuffer(chunk)) throw new TypeError('data should be a string, Buffer or Uint8Array');
355
- if (utils.isFunction(encodingOrCallback)) {
346
+ if (utils.isFunction(encoding)) {
356
347
  // @ts-ignore
357
- cb = encodingOrCallback;
358
- encodingOrCallback = null;
348
+ cb = encoding;
349
+ encoding = null;
359
350
  }
360
351
  // Ignore empty buffers, since writing them doesn't invoke the callback
361
352
  // https://github.com/nodejs/node/issues/22066
@@ -368,10 +359,10 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
368
359
  m._requestBodyLength += chunk.length;
369
360
  m._requestBodyBuffers.push({
370
361
  data: chunk,
371
- encoding: encodingOrCallback
362
+ encoding
372
363
  });
373
364
  // @ts-ignore
374
- m._currentRequest.write(chunk, encodingOrCallback, cb);
365
+ m._currentRequest.write(chunk, encoding, cb);
375
366
  } else {
376
367
  m.emit('error', new MaxBodyLengthExceededError());
377
368
  m.abort();
@@ -396,7 +387,7 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
396
387
  cb = encoding;
397
388
  encoding = null;
398
389
  }
399
- // ! 数据写入时连接,pipe 时可设置 header
390
+ // ! 创建实例时不连接,数据写入时发起连接,连接后无法设置 header,因此 pipe 时可设置 header
400
391
  if (!m._currentRequest) m.request();
401
392
  // Write data if needed and end
402
393
  if (!chunk) {
@@ -559,10 +550,7 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
559
550
  // even if the specific status code is not understood.
560
551
  // If the response is not a redirect; return it as-is
561
552
  const { location } = response.headers;
562
- log({
563
- statusCode,
564
- headers: response.headers
565
- }, 'processResponse');
553
+ // log({statusCode, headers: response.headers}, 'processResponse')
566
554
  if (!location || opt.followRedirects === false || statusCode < 300 || statusCode >= 400) {
567
555
  // 非重定向,返回给原始回调处理
568
556
  response.responseUrl = m._currentUrl;
@@ -673,11 +661,11 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
673
661
  ];
674
662
  // 'transfer-encoding': 'chunked'时,无content-length,axios v1.2 不能自动解压
675
663
  const responseLength = +res.headers['content-length'];
676
- log('processStream', {
677
- statusCode: res.statusCode,
678
- responseLength,
679
- headers: res.headers
680
- });
664
+ // log('processStream', {
665
+ // statusCode: res.statusCode,
666
+ // responseLength,
667
+ // headers: res.headers,
668
+ // })
681
669
  if (opt.transformStream) {
682
670
  opt.transformStream.responseLength = responseLength;
683
671
  streams.push(opt.transformStream);
package/lib/utils.js CHANGED
@@ -38,7 +38,7 @@ const preservedUrlFields = [
38
38
  */ function createErrorType(code, message, baseClass) {
39
39
  /**
40
40
  * Create constructor
41
- * @param {*} properties
41
+ * @param {*} properties
42
42
  */ function CustomError(properties) {
43
43
  // istanbul ignore else
44
44
  if (isFunction(Error.captureStackTrace)) {
@@ -132,9 +132,9 @@ const noop = ()=>{};
132
132
  return URL && value instanceof URL;
133
133
  }
134
134
  /**
135
- *
136
- * @param {*} rs
137
- * @returns
135
+ *
136
+ * @param {*} rs
137
+ * @returns
138
138
  */ function isReadStream(rs) {
139
139
  return rs.readable && rs.path && rs.mode;
140
140
  }
@@ -217,6 +217,13 @@ const noop = ()=>{};
217
217
  code === 204 || // Not Modified
218
218
  code === 304;
219
219
  }
220
+ /**
221
+ * Determine if a value is a Stream
222
+ *
223
+ * @param {*} val The value to test
224
+ *
225
+ * @returns {boolean} True if value is a Stream, otherwise false
226
+ */ const isStream = (val)=>isObject(val) && isFunction(val.pipe);
220
227
  export default {
221
228
  createErrorType,
222
229
  InvalidUrlError,
@@ -230,6 +237,7 @@ export default {
230
237
  isObject,
231
238
  isURL,
232
239
  isReadStream,
240
+ isStream,
233
241
  noop,
234
242
  parseUrl,
235
243
  spreadUrlObject,
package/package.json CHANGED
@@ -2,12 +2,15 @@
2
2
  "name": "@wiajs/request",
3
3
  "description": "Stream HTTP request client.",
4
4
  "keywords": ["http", "simple", "util", "utility"],
5
- "version": "3.0.20",
5
+ "version": "3.0.23",
6
6
  "type": "module",
7
7
  "main": "index.js",
8
8
  "types": "types/index.d.ts",
9
9
  "exports": {
10
10
  ".": {
11
+ "types": {
12
+ "default": "./types/index.d.ts"
13
+ },
11
14
  "node": {
12
15
  "import": "./index.js",
13
16
  "require": "./dist/request.cjs",