@wiajs/request 3.0.29 → 3.0.30
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 +159 -59
- package/dist/request.mjs +159 -59
- package/lib/index.js +76 -48
- package/lib/request.js +64 -12
- package/package.json +1 -1
- package/types/index.d.ts +35 -9
- package/types/request.d.ts +4 -2
- package/types/utils.d.ts +2 -0
package/dist/request.mjs
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* wia request v3.0.
|
|
2
|
+
* wia request v3.0.30
|
|
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 =
|
|
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
|
|
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,39 @@ class Request extends Duplex {
|
|
|
774
789
|
// 启动 startTimer
|
|
775
790
|
if (m.startTimer) m._currentRequest.once('socket', m.startTimer);
|
|
776
791
|
|
|
777
|
-
//
|
|
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
|
+
log$1.error({errcode: err.code}, 'request');
|
|
806
|
+
switch (err.code) {
|
|
807
|
+
case 'ENOTFOUND':
|
|
808
|
+
m.emit('error', new HostNotfoundError());
|
|
809
|
+
break
|
|
810
|
+
case 'ECONNREFUSED':
|
|
811
|
+
m.emit('error', new ConnRefusedError());
|
|
812
|
+
break
|
|
813
|
+
case 'ETIMEDOUT':
|
|
814
|
+
m.emit('error', new ConnTimedoutError());
|
|
815
|
+
break
|
|
816
|
+
case 'ECONNRESET':
|
|
817
|
+
m.emit('error', new ConnResetError());
|
|
818
|
+
break
|
|
819
|
+
default:
|
|
820
|
+
m.emit('error', utils.createErrorType('ERR_CONNOTHER', `网络错误: ${err.message}`));
|
|
821
|
+
}
|
|
822
|
+
});
|
|
823
|
+
|
|
824
|
+
// 接收req事件,转发 到 request 上发射,网络关闭事件,触发 error
|
|
778
825
|
for (const ev of writeEvents) req.on(ev, writeEventEmit[ev]);
|
|
779
826
|
|
|
780
827
|
// RFC7230§5.3.1: When making a request directly to an origin server, […]
|
|
@@ -823,9 +870,11 @@ class Request extends Duplex {
|
|
|
823
870
|
return R
|
|
824
871
|
}
|
|
825
872
|
|
|
873
|
+
/**
|
|
874
|
+
* 写入错误,释放请求,触发 abort 终止事件
|
|
875
|
+
*/
|
|
826
876
|
abort() {
|
|
827
877
|
destroyRequest(this._currentRequest);
|
|
828
|
-
this._currentRequest.abort();
|
|
829
878
|
this.emit('abort');
|
|
830
879
|
}
|
|
831
880
|
|
|
@@ -889,7 +938,11 @@ class Request extends Duplex {
|
|
|
889
938
|
// log({data: chunk, encoding, cb}, 'write')
|
|
890
939
|
|
|
891
940
|
// Writing is not allowed if end has been called
|
|
892
|
-
if (m._ending)
|
|
941
|
+
if (m._ending) {
|
|
942
|
+
// throw new WriteAfterEndError()
|
|
943
|
+
m.emit('error', new WriteAfterEndError());
|
|
944
|
+
return
|
|
945
|
+
}
|
|
893
946
|
|
|
894
947
|
// ! 数据写入时连接,pipe 时可设置 header
|
|
895
948
|
if (!m._currentRequest) m.request();
|
|
@@ -1084,6 +1137,7 @@ class Request extends Duplex {
|
|
|
1084
1137
|
m.on('error', clearTimer);
|
|
1085
1138
|
m.on('response', clearTimer);
|
|
1086
1139
|
m.on('close', clearTimer);
|
|
1140
|
+
|
|
1087
1141
|
return m
|
|
1088
1142
|
}
|
|
1089
1143
|
|
|
@@ -1274,14 +1328,15 @@ class Request extends Duplex {
|
|
|
1274
1328
|
/**
|
|
1275
1329
|
* 处理响应stream
|
|
1276
1330
|
* 自动解压,透传流,需设置 decompress = false,避免解压数据
|
|
1277
|
-
* @param {
|
|
1331
|
+
* @param {Response} res
|
|
1332
|
+
* @returns {Response | stream.Readable}
|
|
1278
1333
|
*/
|
|
1279
1334
|
processStream(res) {
|
|
1280
1335
|
const m = this;
|
|
1281
1336
|
const {opt} = m;
|
|
1282
1337
|
|
|
1283
1338
|
const streams = [res];
|
|
1284
|
-
|
|
1339
|
+
let responseStream = res;
|
|
1285
1340
|
// 'transfer-encoding': 'chunked'时,无content-length,axios v1.2 不能自动解压
|
|
1286
1341
|
const responseLength = +res.headers['content-length'];
|
|
1287
1342
|
|
|
@@ -1314,6 +1369,7 @@ class Request extends Duplex {
|
|
|
1314
1369
|
case 'compress':
|
|
1315
1370
|
case 'x-compress':
|
|
1316
1371
|
// add the unzipper to the body stream processing pipeline
|
|
1372
|
+
// @ts-ignore
|
|
1317
1373
|
streams.push(zlib.createUnzip(zlibOptions));
|
|
1318
1374
|
|
|
1319
1375
|
// remove the content-encoding in order to not confuse downstream operations
|
|
@@ -1321,9 +1377,11 @@ class Request extends Duplex {
|
|
|
1321
1377
|
break
|
|
1322
1378
|
|
|
1323
1379
|
case 'deflate':
|
|
1380
|
+
// @ts-ignore
|
|
1324
1381
|
streams.push(new ZlibTransform());
|
|
1325
1382
|
|
|
1326
1383
|
// add the unzipper to the body stream processing pipeline
|
|
1384
|
+
// @ts-ignore
|
|
1327
1385
|
streams.push(zlib.createUnzip(zlibOptions));
|
|
1328
1386
|
|
|
1329
1387
|
// remove the content-encoding in order to not confuse downstream operations
|
|
@@ -1332,6 +1390,7 @@ class Request extends Duplex {
|
|
|
1332
1390
|
|
|
1333
1391
|
case 'br':
|
|
1334
1392
|
if (isBrotliSupported) {
|
|
1393
|
+
// @ts-ignore
|
|
1335
1394
|
streams.push(zlib.createBrotliDecompress(brotliOptions));
|
|
1336
1395
|
res.headers['content-encoding'] = undefined;
|
|
1337
1396
|
}
|
|
@@ -1340,10 +1399,13 @@ class Request extends Duplex {
|
|
|
1340
1399
|
}
|
|
1341
1400
|
|
|
1342
1401
|
// 响应流,用于读
|
|
1343
|
-
|
|
1402
|
+
// @ts-ignore
|
|
1403
|
+
responseStream = streams.length > 1 ? stream.pipeline(streams, utils.noop) : streams[0];
|
|
1344
1404
|
// 将内部 responseStream 可读流 映射到 redirectReq
|
|
1345
1405
|
|
|
1406
|
+
// @ts-ignore
|
|
1346
1407
|
m.responseStream = responseStream;
|
|
1408
|
+
// @ts-ignore
|
|
1347
1409
|
responseStream.redirectReq = m; // 事情触发时引用
|
|
1348
1410
|
|
|
1349
1411
|
// stream 模式,事件透传到 请求类
|
|
@@ -1515,7 +1577,9 @@ class Request extends Duplex {
|
|
|
1515
1577
|
}
|
|
1516
1578
|
|
|
1517
1579
|
/**
|
|
1518
|
-
*
|
|
1580
|
+
* 释放请求,触发error事件
|
|
1581
|
+
* 'error' event, and emit a 'close' event.
|
|
1582
|
+
* Calling this will cause remaining data in the response to be dropped and the socket to be destroyed.
|
|
1519
1583
|
* @param {*} request
|
|
1520
1584
|
* @param {*} error
|
|
1521
1585
|
*/
|
|
@@ -1524,7 +1588,7 @@ function destroyRequest(request, error) {
|
|
|
1524
1588
|
request.removeListener(ev, writeEventEmit[ev]);
|
|
1525
1589
|
}
|
|
1526
1590
|
request.on('error', utils.noop);
|
|
1527
|
-
request.destroy(error);
|
|
1591
|
+
request.destroy(error); // 触发 error 事件
|
|
1528
1592
|
}
|
|
1529
1593
|
|
|
1530
1594
|
/**
|
|
@@ -1566,9 +1630,35 @@ function isSubdomain(subdomain, domain) {
|
|
|
1566
1630
|
* 代理模式下,http or https 请求,取决于 proxy 代理服务器,而不是目的服务器。
|
|
1567
1631
|
*/
|
|
1568
1632
|
|
|
1569
|
-
|
|
1570
1633
|
const log = log$2({env: `wia:req:${name(import.meta.url)}`}); // __filename
|
|
1571
1634
|
|
|
1635
|
+
/** @typedef { import('./request').Response} Response */
|
|
1636
|
+
|
|
1637
|
+
/**
|
|
1638
|
+
* @typedef {object} Opts
|
|
1639
|
+
* @prop {Object.<string,string>} [headers]
|
|
1640
|
+
* @prop {string} [url]
|
|
1641
|
+
* @prop {'http:' | 'https:'} [protocol]
|
|
1642
|
+
* @prop {string} [host]
|
|
1643
|
+
* @prop {string} [family]
|
|
1644
|
+
* @prop {string} [path]
|
|
1645
|
+
* @prop {string} [method]
|
|
1646
|
+
* @prop {*} [agent] - 发送请求的agent
|
|
1647
|
+
* @prop {*} [agents] - http、https agent,根据协议自动选择
|
|
1648
|
+
* @prop {*} [body] - body 数据,优先body,其次data
|
|
1649
|
+
* @prop {*} [data] - body 数据
|
|
1650
|
+
* @prop {boolean} [stream] - 以流的方式工作
|
|
1651
|
+
* @prop {boolean} [decompress=true] - 自动解压
|
|
1652
|
+
* @prop {*} [transformStream]
|
|
1653
|
+
* @prop {*} [beforeRedirect]
|
|
1654
|
+
* @prop {boolean} [followRedirects] - 自动完成重定向
|
|
1655
|
+
* @prop {number} [maxRedirects=21] - 最大重定向次数
|
|
1656
|
+
* @prop {number} [maxBodyLength = 0] - body限制,缺省不限
|
|
1657
|
+
* @prop {*} [trackRedirects]
|
|
1658
|
+
*/
|
|
1659
|
+
|
|
1660
|
+
/** @typedef {(res: Response, stream?: stream.Readable) => void} Cb*/
|
|
1661
|
+
|
|
1572
1662
|
utils.createErrorType(
|
|
1573
1663
|
'ERR_STREAM_WRITE_BEEN_ABORTED',
|
|
1574
1664
|
'Request stream has been aborted'
|
|
@@ -1593,10 +1683,10 @@ utils.createErrorType(
|
|
|
1593
1683
|
|
|
1594
1684
|
/**
|
|
1595
1685
|
* 初始化参数
|
|
1596
|
-
* @param {
|
|
1597
|
-
* @param {
|
|
1598
|
-
* @param {
|
|
1599
|
-
* @returns
|
|
1686
|
+
* @param {string | Opts} uri/opts
|
|
1687
|
+
* @param {Opts | Cb} [opts] /cb
|
|
1688
|
+
* @param {Cb} [cb]
|
|
1689
|
+
* @returns {{opts: Opts, cb: Cb}}
|
|
1600
1690
|
*/
|
|
1601
1691
|
function init(uri, opts, cb) {
|
|
1602
1692
|
let R;
|
|
@@ -1605,39 +1695,55 @@ function init(uri, opts, cb) {
|
|
|
1605
1695
|
if (utils.isURL(uri)) uri = utils.spreadUrlObject(uri);
|
|
1606
1696
|
else if (utils.isString(uri)) uri = utils.spreadUrlObject(utils.parseUrl(uri));
|
|
1607
1697
|
else {
|
|
1698
|
+
// @ts-ignore
|
|
1608
1699
|
cb = opts;
|
|
1700
|
+
// @ts-ignore
|
|
1609
1701
|
opts = uri;
|
|
1702
|
+
// @ts-ignore
|
|
1610
1703
|
const {url} = opts;
|
|
1704
|
+
// 有url,解析
|
|
1611
1705
|
if (url) {
|
|
1706
|
+
// @ts-ignore
|
|
1707
|
+
// biome-ignore lint/performance/noDelete: <explanation>
|
|
1612
1708
|
delete opts.url;
|
|
1613
1709
|
if (utils.isURL(url)) uri = utils.spreadUrlObject(url);
|
|
1614
1710
|
else if (utils.isString(url)) uri = utils.spreadUrlObject(utils.parseUrl(url));
|
|
1615
1711
|
} else {
|
|
1616
|
-
|
|
1712
|
+
// @ts-ignore
|
|
1713
|
+
opts = uri; // 不判断 utils.validateUrl(uri)
|
|
1617
1714
|
uri = {};
|
|
1618
1715
|
}
|
|
1619
1716
|
}
|
|
1620
1717
|
|
|
1621
1718
|
if (utils.isFunction(opts)) {
|
|
1719
|
+
// @ts-ignore
|
|
1622
1720
|
cb = opts;
|
|
1623
|
-
opts =
|
|
1721
|
+
opts = {};
|
|
1624
1722
|
}
|
|
1625
1723
|
|
|
1626
1724
|
// copy options
|
|
1627
1725
|
opts = {
|
|
1726
|
+
// @ts-ignore
|
|
1628
1727
|
...uri,
|
|
1629
1728
|
...opts,
|
|
1630
1729
|
};
|
|
1631
1730
|
|
|
1731
|
+
// @ts-ignore
|
|
1632
1732
|
if (!utils.isString(opts.host) && !utils.isString(opts.hostname)) opts.hostname = '::1';
|
|
1733
|
+
// @ts-ignore
|
|
1633
1734
|
if (opts.method) opts.method = opts.method.toUpperCase();
|
|
1634
1735
|
|
|
1635
|
-
|
|
1736
|
+
// @ts-ignore
|
|
1737
|
+
// follow-redirects does not skip comparison, so it should always succeed for axios -1 unlimited
|
|
1738
|
+
opts.maxBodyLength = opts.maxBodyLength ?? Number.POSITIVE_INFINITY;
|
|
1739
|
+
|
|
1740
|
+
R = {opts, cb};
|
|
1636
1741
|
// log({R}, 'init')
|
|
1637
1742
|
} catch (e) {
|
|
1638
1743
|
log.err(e, 'init');
|
|
1639
1744
|
}
|
|
1640
1745
|
|
|
1746
|
+
// @ts-ignore
|
|
1641
1747
|
return R
|
|
1642
1748
|
}
|
|
1643
1749
|
|
|
@@ -1648,19 +1754,26 @@ function init(uri, opts, cb) {
|
|
|
1648
1754
|
* 注意变参 (options[, callback]) or (url[, options][, callback])
|
|
1649
1755
|
maxRedirects: _.maxRedirects,
|
|
1650
1756
|
maxBodyLength: _.maxBodyLength,
|
|
1651
|
-
* @param {
|
|
1652
|
-
* @param {
|
|
1653
|
-
* @param {
|
|
1654
|
-
* @returns
|
|
1757
|
+
* @param {string | Opts} uri /options
|
|
1758
|
+
* @param {Opts | Cb} [options] /callback
|
|
1759
|
+
* @param {Cb} [callback] /null
|
|
1760
|
+
* @returns {Request}
|
|
1655
1761
|
*/
|
|
1656
1762
|
function request(uri, options, callback) {
|
|
1657
1763
|
let R = null;
|
|
1658
1764
|
|
|
1659
1765
|
try {
|
|
1766
|
+
// @ts-ignore
|
|
1660
1767
|
const {opts, cb} = init(uri, options, callback);
|
|
1661
|
-
// log({uri, options, opts}, 'request')
|
|
1662
|
-
|
|
1768
|
+
// log.error({uri, options, opts}, 'request')
|
|
1769
|
+
|
|
1663
1770
|
const {data, stream} = opts;
|
|
1771
|
+
// data 在本函数完成处理,不传递到 request
|
|
1772
|
+
opts.data = undefined;
|
|
1773
|
+
|
|
1774
|
+
// @ts-ignore
|
|
1775
|
+
const req = new Request(opts, cb);
|
|
1776
|
+
|
|
1664
1777
|
// 非流模式,自动发送请求,流模式通过流写入发送
|
|
1665
1778
|
if (!stream) {
|
|
1666
1779
|
// 发送数据
|
|
@@ -1687,8 +1800,12 @@ function request(uri, options, callback) {
|
|
|
1687
1800
|
}
|
|
1688
1801
|
});
|
|
1689
1802
|
|
|
1803
|
+
// log.error({data}, 'request data.pipe')
|
|
1690
1804
|
data.pipe(req); // 写入数据流
|
|
1691
|
-
} else
|
|
1805
|
+
} else {
|
|
1806
|
+
// log.error({data}, 'request req.end')
|
|
1807
|
+
req.end(data); // 写入数据
|
|
1808
|
+
}
|
|
1692
1809
|
}
|
|
1693
1810
|
|
|
1694
1811
|
R = req;
|
|
@@ -1705,40 +1822,23 @@ function request(uri, options, callback) {
|
|
|
1705
1822
|
* 复杂数据,请使用 @wiajs/req库(fork from axios),该库封装了当前库,提供了更多功能
|
|
1706
1823
|
* organize params for patch, post, put, head, del
|
|
1707
1824
|
* @param {string} verb
|
|
1708
|
-
* @returns {
|
|
1825
|
+
* @returns {(url: string | Opts, opts?: Opts | Cb, cb?: Cb) => void}}
|
|
1709
1826
|
*/
|
|
1710
1827
|
function fn(verb) {
|
|
1711
1828
|
const method = verb.toUpperCase();
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1829
|
+
/**
|
|
1830
|
+
*
|
|
1831
|
+
* @param {string | Opts} uri /options
|
|
1832
|
+
* @param {Opts | Cb} [opts] /callback
|
|
1833
|
+
* @param {Cb} [cb] /null
|
|
1834
|
+
* @returns
|
|
1835
|
+
*/
|
|
1836
|
+
function fn(uri, opts, cb) {
|
|
1837
|
+
// @ts-ignore
|
|
1716
1838
|
opts.method = method;
|
|
1717
|
-
|
|
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
|
|
1839
|
+
return request(uri, opts, cb)
|
|
1741
1840
|
}
|
|
1841
|
+
return fn
|
|
1742
1842
|
}
|
|
1743
1843
|
|
|
1744
1844
|
// define like this to please codeintel/intellisense IDEs
|
package/lib/index.js
CHANGED
|
@@ -3,14 +3,36 @@
|
|
|
3
3
|
* used by axios
|
|
4
4
|
* 修改以支持http、https 代理服务器
|
|
5
5
|
* 代理模式下,http or https 请求,取决于 proxy 代理服务器,而不是目的服务器。
|
|
6
|
-
*/ import
|
|
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
|
-
|
|
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';
|
|
@@ -25,10 +47,10 @@ const WritebBeenAbortedError = utils.createErrorType('ERR_STREAM_WRITE_BEEN_ABOR
|
|
|
25
47
|
* 支持隧道及非隧道、http(s)代理
|
|
26
48
|
*/ /**
|
|
27
49
|
* 初始化参数
|
|
28
|
-
* @param {
|
|
29
|
-
* @param {
|
|
30
|
-
* @param {
|
|
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,53 @@ 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
|
-
|
|
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 =
|
|
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;
|
|
62
99
|
R = {
|
|
63
|
-
opts
|
|
64
|
-
cb
|
|
100
|
+
opts,
|
|
101
|
+
cb
|
|
65
102
|
};
|
|
66
103
|
// log({R}, 'init')
|
|
67
104
|
} catch (e) {
|
|
68
105
|
log.err(e, 'init');
|
|
69
106
|
}
|
|
107
|
+
// @ts-ignore
|
|
70
108
|
return R;
|
|
71
109
|
}
|
|
72
110
|
/**
|
|
@@ -76,17 +114,21 @@ const WritebBeenAbortedError = utils.createErrorType('ERR_STREAM_WRITE_BEEN_ABOR
|
|
|
76
114
|
* 注意变参 (options[, callback]) or (url[, options][, callback])
|
|
77
115
|
maxRedirects: _.maxRedirects,
|
|
78
116
|
maxBodyLength: _.maxBodyLength,
|
|
79
|
-
* @param {
|
|
80
|
-
* @param {
|
|
81
|
-
* @param {
|
|
82
|
-
* @returns
|
|
117
|
+
* @param {string | Opts} uri /options
|
|
118
|
+
* @param {Opts | Cb} [options] /callback
|
|
119
|
+
* @param {Cb} [callback] /null
|
|
120
|
+
* @returns {Request}
|
|
83
121
|
*/ function request(uri, options, callback) {
|
|
84
122
|
let R = null;
|
|
85
123
|
try {
|
|
124
|
+
// @ts-ignore
|
|
86
125
|
const { opts, cb } = init(uri, options, callback);
|
|
87
|
-
// log({uri, options, opts}, 'request')
|
|
88
|
-
const req = new Request(opts, cb);
|
|
126
|
+
// log.error({uri, options, opts}, 'request')
|
|
89
127
|
const { data, stream } = opts;
|
|
128
|
+
// data 在本函数完成处理,不传递到 request
|
|
129
|
+
opts.data = undefined;
|
|
130
|
+
// @ts-ignore
|
|
131
|
+
const req = new Request(opts, cb);
|
|
90
132
|
// 非流模式,自动发送请求,流模式通过流写入发送
|
|
91
133
|
if (!stream) {
|
|
92
134
|
// 发送数据
|
|
@@ -106,9 +148,14 @@ const WritebBeenAbortedError = utils.createErrorType('ERR_STREAM_WRITE_BEEN_ABOR
|
|
|
106
148
|
// throw new WritebBeenAbortedError()
|
|
107
149
|
}
|
|
108
150
|
});
|
|
151
|
+
// log.error({data}, 'request data.pipe')
|
|
109
152
|
data.pipe(req) // 写入数据流
|
|
110
153
|
;
|
|
111
|
-
} else
|
|
154
|
+
} else {
|
|
155
|
+
// log.error({data}, 'request req.end')
|
|
156
|
+
req.end(data) // 写入数据
|
|
157
|
+
;
|
|
158
|
+
}
|
|
112
159
|
}
|
|
113
160
|
R = req;
|
|
114
161
|
} catch (e) {
|
|
@@ -122,40 +169,21 @@ const WritebBeenAbortedError = utils.createErrorType('ERR_STREAM_WRITE_BEEN_ABOR
|
|
|
122
169
|
* 复杂数据,请使用 @wiajs/req库(fork from axios),该库封装了当前库,提供了更多功能
|
|
123
170
|
* organize params for patch, post, put, head, del
|
|
124
171
|
* @param {string} verb
|
|
125
|
-
* @returns {
|
|
172
|
+
* @returns {(url: string | Opts, opts?: Opts | Cb, cb?: Cb) => void}}
|
|
126
173
|
*/ function fn(verb) {
|
|
127
174
|
const method = verb.toUpperCase();
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
175
|
+
/**
|
|
176
|
+
*
|
|
177
|
+
* @param {string | Opts} uri /options
|
|
178
|
+
* @param {Opts | Cb} [opts] /callback
|
|
179
|
+
* @param {Cb} [cb] /null
|
|
180
|
+
* @returns
|
|
181
|
+
*/ function fn(uri, opts, cb) {
|
|
182
|
+
// @ts-ignore
|
|
131
183
|
opts.method = method;
|
|
132
|
-
|
|
133
|
-
|
|
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
|
-
};
|
|
184
|
+
return request(uri, opts, cb);
|
|
185
|
+
}
|
|
186
|
+
return fn;
|
|
159
187
|
}
|
|
160
188
|
// define like this to please codeintel/intellisense IDEs
|
|
161
189
|
request.get = fn('get');
|