@wiajs/request 3.0.29 → 3.0.31

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.mjs CHANGED
@@ -1,14 +1,14 @@
1
1
  /*!
2
- * wia request v3.0.29
2
+ * wia request v3.0.31
3
3
  * (c) 2022-2024 Sibyl Yu and contributors
4
4
  * Released under the MIT License.
5
5
  */
6
+ import stream, { Duplex } from 'node:stream';
6
7
  import { log as log$2, name } from '@wiajs/log';
7
8
  import http from 'node:http';
8
9
  import https from 'node:https';
9
10
  import assert from 'node:assert';
10
11
  import url from 'node:url';
11
- import stream, { Duplex } from 'node:stream';
12
12
  import zlib from 'node:zlib';
13
13
  import mime from 'mime-types';
14
14
 
@@ -464,7 +464,7 @@ const log$1 = log$2({env: `wia:req:${name(import.meta.url)}`}); // __filename
464
464
  * @prop {*} [beforeRedirect]
465
465
  * @prop {boolean} [followRedirects]
466
466
  * @prop {number} [maxRedirects=21]
467
- * @prop {number} [maxBodyLength = 0]
467
+ * @prop {number} [maxBodyLength = -1]
468
468
  * @prop {*} [trackRedirects]
469
469
  * @prop {*} [data]
470
470
  */
@@ -475,7 +475,7 @@ const log$1 = log$2({env: `wia:req:${name(import.meta.url)}`}); // __filename
475
475
  * @prop {number} [responseStartTime]
476
476
  */
477
477
 
478
- /** @typedef { http.IncomingMessage & ResponseExt} Response*/
478
+ /** @typedef { http.IncomingMessage & ResponseExt} Response */
479
479
 
480
480
  const httpModules = {'http:': http, 'https:': https};
481
481
 
@@ -525,12 +525,12 @@ const writeEvents = [
525
525
  'connect',
526
526
  'continue',
527
527
  'drain',
528
- 'error',
528
+ // 'error', // 单独处理,未注册 'error' 事件处理程序,错误将冒泡到全局导致程序崩溃
529
529
  'finish',
530
530
  'information',
531
531
  'pipe',
532
532
  // 'response', 由 processResponse 触发
533
- 'socket',
533
+ 'socket', // 建立连接时触发
534
534
  'timeout',
535
535
  'unpipe',
536
536
  'upgrade',
@@ -542,7 +542,7 @@ for (const ev of writeEvents)
542
542
  writeEventEmit[ev] = /** @param {...any} args */ function (...args) {
543
543
  const m = this; // 事件回调,this === clientRequest 实例
544
544
  // log('req event', {ev})
545
- m.redirectReq.emit(ev, ...args); // req 事情映射到 redirectReq 上触发
545
+ m.redirectReq.emit(ev, ...args); // 内部请求req 事情转发到 Request
546
546
  };
547
547
 
548
548
  // stream.Readable,在响应流上转发读流取事件
@@ -575,6 +575,21 @@ const MaxBodyLengthExceededError = utils.createErrorType(
575
575
 
576
576
  const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', 'write after end');
577
577
 
578
+ // request err
579
+ const HostNotfoundError = utils.createErrorType('ERR_HOSTNOTFOUND', 'DNS 解析失败,主机名可能无效');
580
+ const ConnRefusedError = utils.createErrorType(
581
+ 'ERR_CONNREFUSED',
582
+ '连接被拒绝,目标服务器可能不可用'
583
+ );
584
+ const ConnTimedoutError = utils.createErrorType(
585
+ 'ERR_CONNTIMEDOUT',
586
+ '请求超时,请检查网络连接或服务器负载'
587
+ );
588
+ const ConnResetError = utils.createErrorType(
589
+ 'ERR_CONNRESET',
590
+ '连接被重置,可能是网络问题或服务器关闭了连接'
591
+ );
592
+
578
593
  /**
579
594
  * An HTTP(S) request that can be redirected
580
595
  * wrap http.ClientRequest
@@ -774,7 +789,41 @@ class Request extends Duplex {
774
789
  // 启动 startTimer
775
790
  if (m.startTimer) m._currentRequest.once('socket', m.startTimer);
776
791
 
777
- // 接收req事件,转发 redirectReq 发射
792
+ // set tcp keep alive to prevent drop connection by peer
793
+ req.on(
794
+ 'socket',
795
+ /** @param {*} socket */ socket => {
796
+ // default interval of sending ack packet is 1 minute
797
+ socket.setKeepAlive(true, 1000 * 60);
798
+ }
799
+ );
800
+
801
+ // 请求error单独处理
802
+ // 'error' 事件处理,避免错误将冒泡到全局导致程序崩溃
803
+ req.on('error', err => {
804
+ destroyRequest(req); // 释放资源
805
+ // @ts-ignore
806
+ log$1.error({errcode: err?.code}, 'request');
807
+ // @ts-ignore
808
+ switch (err?.code) {
809
+ case 'ENOTFOUND':
810
+ m.emit('error', new HostNotfoundError());
811
+ break
812
+ case 'ECONNREFUSED':
813
+ m.emit('error', new ConnRefusedError());
814
+ break
815
+ case 'ETIMEDOUT':
816
+ m.emit('error', new ConnTimedoutError());
817
+ break
818
+ case 'ECONNRESET':
819
+ m.emit('error', new ConnResetError());
820
+ break
821
+ default:
822
+ m.emit('error', utils.createErrorType('ERR_CONNOTHER', `网络错误: ${err.message}`));
823
+ }
824
+ });
825
+
826
+ // 接收req事件,转发 到 request 上发射,网络关闭事件,触发 error
778
827
  for (const ev of writeEvents) req.on(ev, writeEventEmit[ev]);
779
828
 
780
829
  // RFC7230§5.3.1: When making a request directly to an origin server, […]
@@ -823,9 +872,11 @@ class Request extends Duplex {
823
872
  return R
824
873
  }
825
874
 
875
+ /**
876
+ * 写入错误,释放请求,触发 abort 终止事件
877
+ */
826
878
  abort() {
827
879
  destroyRequest(this._currentRequest);
828
- this._currentRequest.abort();
829
880
  this.emit('abort');
830
881
  }
831
882
 
@@ -889,7 +940,11 @@ class Request extends Duplex {
889
940
  // log({data: chunk, encoding, cb}, 'write')
890
941
 
891
942
  // Writing is not allowed if end has been called
892
- if (m._ending) throw new WriteAfterEndError()
943
+ if (m._ending) {
944
+ // throw new WriteAfterEndError()
945
+ m.emit('error', new WriteAfterEndError());
946
+ return
947
+ }
893
948
 
894
949
  // ! 数据写入时连接,pipe 时可设置 header
895
950
  if (!m._currentRequest) m.request();
@@ -1084,6 +1139,7 @@ class Request extends Duplex {
1084
1139
  m.on('error', clearTimer);
1085
1140
  m.on('response', clearTimer);
1086
1141
  m.on('close', clearTimer);
1142
+
1087
1143
  return m
1088
1144
  }
1089
1145
 
@@ -1274,14 +1330,15 @@ class Request extends Duplex {
1274
1330
  /**
1275
1331
  * 处理响应stream
1276
1332
  * 自动解压,透传流,需设置 decompress = false,避免解压数据
1277
- * @param {*} res
1333
+ * @param {Response} res
1334
+ * @returns {Response | stream.Readable}
1278
1335
  */
1279
1336
  processStream(res) {
1280
1337
  const m = this;
1281
1338
  const {opt} = m;
1282
1339
 
1283
1340
  const streams = [res];
1284
-
1341
+ let responseStream = res;
1285
1342
  // 'transfer-encoding': 'chunked'时,无content-length,axios v1.2 不能自动解压
1286
1343
  const responseLength = +res.headers['content-length'];
1287
1344
 
@@ -1314,6 +1371,7 @@ class Request extends Duplex {
1314
1371
  case 'compress':
1315
1372
  case 'x-compress':
1316
1373
  // add the unzipper to the body stream processing pipeline
1374
+ // @ts-ignore
1317
1375
  streams.push(zlib.createUnzip(zlibOptions));
1318
1376
 
1319
1377
  // remove the content-encoding in order to not confuse downstream operations
@@ -1321,9 +1379,11 @@ class Request extends Duplex {
1321
1379
  break
1322
1380
 
1323
1381
  case 'deflate':
1382
+ // @ts-ignore
1324
1383
  streams.push(new ZlibTransform());
1325
1384
 
1326
1385
  // add the unzipper to the body stream processing pipeline
1386
+ // @ts-ignore
1327
1387
  streams.push(zlib.createUnzip(zlibOptions));
1328
1388
 
1329
1389
  // remove the content-encoding in order to not confuse downstream operations
@@ -1332,6 +1392,7 @@ class Request extends Duplex {
1332
1392
 
1333
1393
  case 'br':
1334
1394
  if (isBrotliSupported) {
1395
+ // @ts-ignore
1335
1396
  streams.push(zlib.createBrotliDecompress(brotliOptions));
1336
1397
  res.headers['content-encoding'] = undefined;
1337
1398
  }
@@ -1340,10 +1401,13 @@ class Request extends Duplex {
1340
1401
  }
1341
1402
 
1342
1403
  // 响应流,用于读
1343
- const responseStream = streams.length > 1 ? stream.pipeline(streams, utils.noop) : streams[0];
1404
+ // @ts-ignore
1405
+ responseStream = streams.length > 1 ? stream.pipeline(streams, utils.noop) : streams[0];
1344
1406
  // 将内部 responseStream 可读流 映射到 redirectReq
1345
1407
 
1408
+ // @ts-ignore
1346
1409
  m.responseStream = responseStream;
1410
+ // @ts-ignore
1347
1411
  responseStream.redirectReq = m; // 事情触发时引用
1348
1412
 
1349
1413
  // stream 模式,事件透传到 请求类
@@ -1515,7 +1579,9 @@ class Request extends Duplex {
1515
1579
  }
1516
1580
 
1517
1581
  /**
1518
- *
1582
+ * 释放请求,触发error事件
1583
+ * 'error' event, and emit a 'close' event.
1584
+ * Calling this will cause remaining data in the response to be dropped and the socket to be destroyed.
1519
1585
  * @param {*} request
1520
1586
  * @param {*} error
1521
1587
  */
@@ -1524,7 +1590,7 @@ function destroyRequest(request, error) {
1524
1590
  request.removeListener(ev, writeEventEmit[ev]);
1525
1591
  }
1526
1592
  request.on('error', utils.noop);
1527
- request.destroy(error);
1593
+ request.destroy(error); // 触发 error 事件
1528
1594
  }
1529
1595
 
1530
1596
  /**
@@ -1566,9 +1632,35 @@ function isSubdomain(subdomain, domain) {
1566
1632
  * 代理模式下,http or https 请求,取决于 proxy 代理服务器,而不是目的服务器。
1567
1633
  */
1568
1634
 
1569
-
1570
1635
  const log = log$2({env: `wia:req:${name(import.meta.url)}`}); // __filename
1571
1636
 
1637
+ /** @typedef { import('./request').Response} Response */
1638
+
1639
+ /**
1640
+ * @typedef {object} Opts
1641
+ * @prop {Object.<string,string>} [headers]
1642
+ * @prop {string} [url]
1643
+ * @prop {'http:' | 'https:'} [protocol]
1644
+ * @prop {string} [host]
1645
+ * @prop {string} [family]
1646
+ * @prop {string} [path]
1647
+ * @prop {string} [method]
1648
+ * @prop {*} [agent] - 发送请求的agent
1649
+ * @prop {*} [agents] - http、https agent,根据协议自动选择
1650
+ * @prop {*} [body] - body 数据,优先body,其次data
1651
+ * @prop {*} [data] - body 数据
1652
+ * @prop {boolean} [stream] - 以流的方式工作
1653
+ * @prop {boolean} [decompress=true] - 自动解压
1654
+ * @prop {*} [transformStream]
1655
+ * @prop {*} [beforeRedirect]
1656
+ * @prop {boolean} [followRedirects] - 自动完成重定向
1657
+ * @prop {number} [maxRedirects=21] - 最大重定向次数
1658
+ * @prop {number} [maxBodyLength = 0] - body限制,缺省不限
1659
+ * @prop {*} [trackRedirects]
1660
+ */
1661
+
1662
+ /** @typedef {(res: Response, stream?: stream.Readable) => void} Cb*/
1663
+
1572
1664
  utils.createErrorType(
1573
1665
  'ERR_STREAM_WRITE_BEEN_ABORTED',
1574
1666
  'Request stream has been aborted'
@@ -1581,7 +1673,7 @@ utils.createErrorType(
1581
1673
  const looksLikeBrowser = typeof window !== 'undefined' && typeof document !== 'undefined';
1582
1674
  const looksLikeV8 = utils.isFunction(Error.captureStackTrace);
1583
1675
  if (!looksLikeNode && (looksLikeBrowser || !looksLikeV8)) {
1584
- console.warn('The follow-redirects package should be excluded from browser builds.');
1676
+ log.warn('The follow-redirects package should be excluded from browser builds.');
1585
1677
  }
1586
1678
  })();
1587
1679
 
@@ -1593,10 +1685,10 @@ utils.createErrorType(
1593
1685
 
1594
1686
  /**
1595
1687
  * 初始化参数
1596
- * @param {*} uri/opts
1597
- * @param {*} opts/cb
1598
- * @param {*} cb/null
1599
- * @returns
1688
+ * @param {string | Opts} uri/opts
1689
+ * @param {Opts | Cb} [opts] /cb
1690
+ * @param {Cb} [cb]
1691
+ * @returns {{opts: Opts, cb: Cb}}
1600
1692
  */
1601
1693
  function init(uri, opts, cb) {
1602
1694
  let R;
@@ -1605,39 +1697,59 @@ function init(uri, opts, cb) {
1605
1697
  if (utils.isURL(uri)) uri = utils.spreadUrlObject(uri);
1606
1698
  else if (utils.isString(uri)) uri = utils.spreadUrlObject(utils.parseUrl(uri));
1607
1699
  else {
1700
+ // @ts-ignore
1608
1701
  cb = opts;
1702
+ // @ts-ignore
1609
1703
  opts = uri;
1704
+ // @ts-ignore
1610
1705
  const {url} = opts;
1706
+ // 有url,解析
1611
1707
  if (url) {
1708
+ // @ts-ignore
1709
+ // biome-ignore lint/performance/noDelete: <explanation>
1612
1710
  delete opts.url;
1613
1711
  if (utils.isURL(url)) uri = utils.spreadUrlObject(url);
1614
1712
  else if (utils.isString(url)) uri = utils.spreadUrlObject(utils.parseUrl(url));
1615
1713
  } else {
1616
- opts = utils.validateUrl(uri);
1714
+ // @ts-ignore
1715
+ opts = uri; // 不判断 utils.validateUrl(uri)
1617
1716
  uri = {};
1618
1717
  }
1619
1718
  }
1620
1719
 
1621
1720
  if (utils.isFunction(opts)) {
1721
+ // @ts-ignore
1622
1722
  cb = opts;
1623
- opts = null;
1723
+ opts = {};
1624
1724
  }
1625
1725
 
1626
1726
  // copy options
1627
1727
  opts = {
1728
+ // @ts-ignore
1628
1729
  ...uri,
1629
1730
  ...opts,
1630
1731
  };
1631
1732
 
1733
+ // @ts-ignore
1632
1734
  if (!utils.isString(opts.host) && !utils.isString(opts.hostname)) opts.hostname = '::1';
1735
+ // @ts-ignore
1633
1736
  if (opts.method) opts.method = opts.method.toUpperCase();
1634
1737
 
1635
- R = {opts: opts, cb: cb};
1738
+ // @ts-ignore
1739
+ // follow-redirects does not skip comparison, so it should always succeed for axios -1 unlimited
1740
+ opts.maxBodyLength = opts.maxBodyLength ?? Number.POSITIVE_INFINITY;
1741
+ // @ts-ignore
1742
+ opts.maxRedirects = opts.maxRedirects ?? 21;
1743
+ // @ts-ignore
1744
+ if (opts.maxRedirects === 0) opts.followRedirects = false;
1745
+
1746
+ R = {opts, cb};
1636
1747
  // log({R}, 'init')
1637
1748
  } catch (e) {
1638
1749
  log.err(e, 'init');
1639
1750
  }
1640
1751
 
1752
+ // @ts-ignore
1641
1753
  return R
1642
1754
  }
1643
1755
 
@@ -1648,19 +1760,26 @@ function init(uri, opts, cb) {
1648
1760
  * 注意变参 (options[, callback]) or (url[, options][, callback])
1649
1761
  maxRedirects: _.maxRedirects,
1650
1762
  maxBodyLength: _.maxBodyLength,
1651
- * @param {*} uri/options
1652
- * @param {*} options/callback
1653
- * @param {*} callback/null
1654
- * @returns
1763
+ * @param {string | Opts} uri /options
1764
+ * @param {Opts | Cb} [options] /callback
1765
+ * @param {Cb} [callback] /null
1766
+ * @returns {Request}
1655
1767
  */
1656
1768
  function request(uri, options, callback) {
1657
1769
  let R = null;
1658
1770
 
1659
1771
  try {
1772
+ // @ts-ignore
1660
1773
  const {opts, cb} = init(uri, options, callback);
1661
- // log({uri, options, opts}, 'request')
1662
- const req = new Request(opts, cb);
1774
+ // log.error({uri, options, opts}, 'request')
1775
+
1663
1776
  const {data, stream} = opts;
1777
+ // data 在本函数完成处理,不传递到 request
1778
+ opts.data = undefined;
1779
+
1780
+ // @ts-ignore
1781
+ const req = new Request(opts, cb);
1782
+
1664
1783
  // 非流模式,自动发送请求,流模式通过流写入发送
1665
1784
  if (!stream) {
1666
1785
  // 发送数据
@@ -1687,8 +1806,12 @@ function request(uri, options, callback) {
1687
1806
  }
1688
1807
  });
1689
1808
 
1809
+ // log.error({data}, 'request data.pipe')
1690
1810
  data.pipe(req); // 写入数据流
1691
- } else req.end(data);
1811
+ } else {
1812
+ // log.error({data}, 'request req.end')
1813
+ req.end(data); // 写入数据
1814
+ }
1692
1815
  }
1693
1816
 
1694
1817
  R = req;
@@ -1705,40 +1828,23 @@ function request(uri, options, callback) {
1705
1828
  * 复杂数据,请使用 @wiajs/req库(fork from axios),该库封装了当前库,提供了更多功能
1706
1829
  * organize params for patch, post, put, head, del
1707
1830
  * @param {string} verb
1708
- * @returns {Request} Duplex
1831
+ * @returns {(url: string | Opts, opts?: Opts | Cb, cb?: Cb) => void}}
1709
1832
  */
1710
1833
  function fn(verb) {
1711
1834
  const method = verb.toUpperCase();
1712
-
1713
- // @ts-ignore
1714
- return (uri, options, callback) => {
1715
- const {opts, cb} = init(uri, options, callback);
1835
+ /**
1836
+ *
1837
+ * @param {string | Opts} uri /options
1838
+ * @param {Opts | Cb} [opts] /callback
1839
+ * @param {Cb} [cb] /null
1840
+ * @returns
1841
+ */
1842
+ function fn(uri, opts, cb) {
1843
+ // @ts-ignore
1716
1844
  opts.method = method;
1717
- const req = new Request(opts, cb);
1718
- const {data, stream} = opts;
1719
- // 非流模式,自动发送请求,流模式通过流写入发送
1720
- if (!stream) {
1721
- // 发送数据
1722
- if (utils.isStream(data)) {
1723
-
1724
- data.on('end', () => {
1725
- });
1726
-
1727
- data.once(
1728
- 'error',
1729
- /** @param {*} err */ err => {
1730
- // req.destroy(err)
1731
- }
1732
- );
1733
-
1734
- data.on('close', () => {
1735
- });
1736
-
1737
- data.pipe(req); // 写入数据流
1738
- } else req.end(data);
1739
- }
1740
- return req
1845
+ return request(uri, opts, cb)
1741
1846
  }
1847
+ return fn
1742
1848
  }
1743
1849
 
1744
1850
  // define like this to please codeintel/intellisense IDEs
package/lib/index.js CHANGED
@@ -3,20 +3,42 @@
3
3
  * used by axios
4
4
  * 修改以支持http、https 代理服务器
5
5
  * 代理模式下,http or https 请求,取决于 proxy 代理服务器,而不是目的服务器。
6
- */ import { log as Log, name } from '@wiajs/log';
6
+ */ import stream from 'node:stream';
7
+ import { log as Log, name } from '@wiajs/log';
7
8
  import Request from './request.js';
8
9
  import utils from './utils.js';
9
10
  const log = Log({
10
11
  env: `wia:req:${name(import.meta.url)}`
11
12
  }) // __filename
12
13
  ;
13
- const WritebBeenAbortedError = utils.createErrorType('ERR_STREAM_WRITE_BEEN_ABORTED', 'Request stream has been aborted');
14
+ /** @typedef { import('./request').Response} Response */ /**
15
+ * @typedef {object} Opts
16
+ * @prop {Object.<string,string>} [headers]
17
+ * @prop {string} [url]
18
+ * @prop {'http:' | 'https:'} [protocol]
19
+ * @prop {string} [host]
20
+ * @prop {string} [family]
21
+ * @prop {string} [path]
22
+ * @prop {string} [method]
23
+ * @prop {*} [agent] - 发送请求的agent
24
+ * @prop {*} [agents] - http、https agent,根据协议自动选择
25
+ * @prop {*} [body] - body 数据,优先body,其次data
26
+ * @prop {*} [data] - body 数据
27
+ * @prop {boolean} [stream] - 以流的方式工作
28
+ * @prop {boolean} [decompress=true] - 自动解压
29
+ * @prop {*} [transformStream]
30
+ * @prop {*} [beforeRedirect]
31
+ * @prop {boolean} [followRedirects] - 自动完成重定向
32
+ * @prop {number} [maxRedirects=21] - 最大重定向次数
33
+ * @prop {number} [maxBodyLength = 0] - body限制,缺省不限
34
+ * @prop {*} [trackRedirects]
35
+ */ /** @typedef {(res: Response, stream?: stream.Readable) => void} Cb*/ const WritebBeenAbortedError = utils.createErrorType('ERR_STREAM_WRITE_BEEN_ABORTED', 'Request stream has been aborted');
14
36
  (function detectUnsupportedEnvironment() {
15
37
  const looksLikeNode = typeof process !== 'undefined';
16
38
  const looksLikeBrowser = typeof window !== 'undefined' && typeof document !== 'undefined';
17
39
  const looksLikeV8 = utils.isFunction(Error.captureStackTrace);
18
40
  if (!looksLikeNode && (looksLikeBrowser || !looksLikeV8)) {
19
- console.warn('The follow-redirects package should be excluded from browser builds.');
41
+ log.warn('The follow-redirects package should be excluded from browser builds.');
20
42
  }
21
43
  })();
22
44
  /**
@@ -25,10 +47,10 @@ const WritebBeenAbortedError = utils.createErrorType('ERR_STREAM_WRITE_BEEN_ABOR
25
47
  * 支持隧道及非隧道、http(s)代理
26
48
  */ /**
27
49
  * 初始化参数
28
- * @param {*} uri/opts
29
- * @param {*} opts/cb
30
- * @param {*} cb/null
31
- * @returns
50
+ * @param {string | Opts} uri/opts
51
+ * @param {Opts | Cb} [opts] /cb
52
+ * @param {Cb} [cb]
53
+ * @returns {{opts: Opts, cb: Cb}}
32
54
  */ function init(uri, opts, cb) {
33
55
  let R;
34
56
  try {
@@ -36,37 +58,57 @@ const WritebBeenAbortedError = utils.createErrorType('ERR_STREAM_WRITE_BEEN_ABOR
36
58
  if (utils.isURL(uri)) uri = utils.spreadUrlObject(uri);
37
59
  else if (utils.isString(uri)) uri = utils.spreadUrlObject(utils.parseUrl(uri));
38
60
  else {
61
+ // @ts-ignore
39
62
  cb = opts;
63
+ // @ts-ignore
40
64
  opts = uri;
65
+ // @ts-ignore
41
66
  const { url } = opts;
67
+ // 有url,解析
42
68
  if (url) {
69
+ // @ts-ignore
70
+ // biome-ignore lint/performance/noDelete: <explanation>
43
71
  delete opts.url;
44
72
  if (utils.isURL(url)) uri = utils.spreadUrlObject(url);
45
73
  else if (utils.isString(url)) uri = utils.spreadUrlObject(utils.parseUrl(url));
46
74
  } else {
47
- opts = utils.validateUrl(uri);
75
+ // @ts-ignore
76
+ opts = uri // 不判断 utils.validateUrl(uri)
77
+ ;
48
78
  uri = {};
49
79
  }
50
80
  }
51
81
  if (utils.isFunction(opts)) {
82
+ // @ts-ignore
52
83
  cb = opts;
53
- opts = null;
84
+ opts = {};
54
85
  }
55
86
  // copy options
56
87
  opts = {
88
+ // @ts-ignore
57
89
  ...uri,
58
90
  ...opts
59
91
  };
92
+ // @ts-ignore
60
93
  if (!utils.isString(opts.host) && !utils.isString(opts.hostname)) opts.hostname = '::1';
94
+ // @ts-ignore
61
95
  if (opts.method) opts.method = opts.method.toUpperCase();
96
+ // @ts-ignore
97
+ // follow-redirects does not skip comparison, so it should always succeed for axios -1 unlimited
98
+ opts.maxBodyLength = opts.maxBodyLength ?? Number.POSITIVE_INFINITY;
99
+ // @ts-ignore
100
+ opts.maxRedirects = opts.maxRedirects ?? 21;
101
+ // @ts-ignore
102
+ if (opts.maxRedirects === 0) opts.followRedirects = false;
62
103
  R = {
63
- opts: opts,
64
- cb: cb
104
+ opts,
105
+ cb
65
106
  };
66
107
  // log({R}, 'init')
67
108
  } catch (e) {
68
109
  log.err(e, 'init');
69
110
  }
111
+ // @ts-ignore
70
112
  return R;
71
113
  }
72
114
  /**
@@ -76,17 +118,21 @@ const WritebBeenAbortedError = utils.createErrorType('ERR_STREAM_WRITE_BEEN_ABOR
76
118
  * 注意变参 (options[, callback]) or (url[, options][, callback])
77
119
  maxRedirects: _.maxRedirects,
78
120
  maxBodyLength: _.maxBodyLength,
79
- * @param {*} uri/options
80
- * @param {*} options/callback
81
- * @param {*} callback/null
82
- * @returns
121
+ * @param {string | Opts} uri /options
122
+ * @param {Opts | Cb} [options] /callback
123
+ * @param {Cb} [callback] /null
124
+ * @returns {Request}
83
125
  */ function request(uri, options, callback) {
84
126
  let R = null;
85
127
  try {
128
+ // @ts-ignore
86
129
  const { opts, cb } = init(uri, options, callback);
87
- // log({uri, options, opts}, 'request')
88
- const req = new Request(opts, cb);
130
+ // log.error({uri, options, opts}, 'request')
89
131
  const { data, stream } = opts;
132
+ // data 在本函数完成处理,不传递到 request
133
+ opts.data = undefined;
134
+ // @ts-ignore
135
+ const req = new Request(opts, cb);
90
136
  // 非流模式,自动发送请求,流模式通过流写入发送
91
137
  if (!stream) {
92
138
  // 发送数据
@@ -106,9 +152,14 @@ const WritebBeenAbortedError = utils.createErrorType('ERR_STREAM_WRITE_BEEN_ABOR
106
152
  // throw new WritebBeenAbortedError()
107
153
  }
108
154
  });
155
+ // log.error({data}, 'request data.pipe')
109
156
  data.pipe(req) // 写入数据流
110
157
  ;
111
- } else req.end(data);
158
+ } else {
159
+ // log.error({data}, 'request req.end')
160
+ req.end(data) // 写入数据
161
+ ;
162
+ }
112
163
  }
113
164
  R = req;
114
165
  } catch (e) {
@@ -122,40 +173,21 @@ const WritebBeenAbortedError = utils.createErrorType('ERR_STREAM_WRITE_BEEN_ABOR
122
173
  * 复杂数据,请使用 @wiajs/req库(fork from axios),该库封装了当前库,提供了更多功能
123
174
  * organize params for patch, post, put, head, del
124
175
  * @param {string} verb
125
- * @returns {Request} Duplex
176
+ * @returns {(url: string | Opts, opts?: Opts | Cb, cb?: Cb) => void}}
126
177
  */ function fn(verb) {
127
178
  const method = verb.toUpperCase();
128
- // @ts-ignore
129
- return (uri, options, callback)=>{
130
- const { opts, cb } = init(uri, options, callback);
179
+ /**
180
+ *
181
+ * @param {string | Opts} uri /options
182
+ * @param {Opts | Cb} [opts] /callback
183
+ * @param {Cb} [cb] /null
184
+ * @returns
185
+ */ function fn(uri, opts, cb) {
186
+ // @ts-ignore
131
187
  opts.method = method;
132
- const req = new Request(opts, cb);
133
- const { data, stream } = opts;
134
- // 非流模式,自动发送请求,流模式通过流写入发送
135
- if (!stream) {
136
- // 发送数据
137
- if (utils.isStream(data)) {
138
- // Send the request
139
- let ended = false;
140
- let errored = false;
141
- data.on('end', ()=>{
142
- ended = true;
143
- });
144
- data.once('error', /** @param {*} err */ (err)=>{
145
- errored = true;
146
- // req.destroy(err)
147
- });
148
- data.on('close', ()=>{
149
- if (!ended && !errored) {
150
- // throw new WritebBeenAbortedError()
151
- }
152
- });
153
- data.pipe(req) // 写入数据流
154
- ;
155
- } else req.end(data);
156
- }
157
- return req;
158
- };
188
+ return request(uri, opts, cb);
189
+ }
190
+ return fn;
159
191
  }
160
192
  // define like this to please codeintel/intellisense IDEs
161
193
  request.get = fn('get');