@wiajs/request 3.0.2 → 3.0.5
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/index.js +1 -1
- package/lib/index.js +10 -7
- package/lib/request.js +75 -73
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export {default} from './lib'
|
|
1
|
+
export {default} from './lib/index.js'
|
package/lib/index.js
CHANGED
|
@@ -6,14 +6,15 @@
|
|
|
6
6
|
import Request from './request.js';
|
|
7
7
|
import utils from './utils.js';
|
|
8
8
|
const log = Log({
|
|
9
|
-
env: `wia:req:${name(
|
|
10
|
-
})
|
|
9
|
+
env: `wia:req:${name(import.meta.url)}`
|
|
10
|
+
}) // __filename
|
|
11
|
+
;
|
|
11
12
|
(function detectUnsupportedEnvironment() {
|
|
12
13
|
const looksLikeNode = typeof process !== 'undefined';
|
|
13
14
|
const looksLikeBrowser = typeof window !== 'undefined' && typeof document !== 'undefined';
|
|
14
15
|
const looksLikeV8 = utils.isFunction(Error.captureStackTrace);
|
|
15
16
|
if (!looksLikeNode && (looksLikeBrowser || !looksLikeV8)) {
|
|
16
|
-
|
|
17
|
+
console.warn('The follow-redirects package should be excluded from browser builds.');
|
|
17
18
|
}
|
|
18
19
|
})();
|
|
19
20
|
/**
|
|
@@ -27,6 +28,7 @@ const log = Log({
|
|
|
27
28
|
* @param {*} callback
|
|
28
29
|
* @returns
|
|
29
30
|
*/ function init(uri, options, callback) {
|
|
31
|
+
let R;
|
|
30
32
|
try {
|
|
31
33
|
// Parse parameters, ensuring that input is an object
|
|
32
34
|
if (utils.isURL(uri)) uri = utils.spreadUrlObject(uri);
|
|
@@ -50,6 +52,7 @@ const log = Log({
|
|
|
50
52
|
opts: options,
|
|
51
53
|
cb: callback
|
|
52
54
|
};
|
|
55
|
+
// log({R}, 'init')
|
|
53
56
|
} catch (e) {
|
|
54
57
|
log.err(e, 'init');
|
|
55
58
|
}
|
|
@@ -66,15 +69,14 @@ const log = Log({
|
|
|
66
69
|
* @param {*} callback/null
|
|
67
70
|
* @returns
|
|
68
71
|
*/ function request(uri, options, callback) {
|
|
69
|
-
let
|
|
72
|
+
let R = null;
|
|
70
73
|
try {
|
|
71
74
|
const { opts, cb } = init(uri, options, callback);
|
|
72
|
-
|
|
73
|
-
R1 = new Request(opts, cb);
|
|
75
|
+
R = new Request(opts, cb);
|
|
74
76
|
} catch (e) {
|
|
75
77
|
log.err(e, 'request');
|
|
76
78
|
}
|
|
77
|
-
return
|
|
79
|
+
return R;
|
|
78
80
|
}
|
|
79
81
|
/**
|
|
80
82
|
* 执行简单的非stream数据请求
|
|
@@ -84,6 +86,7 @@ const log = Log({
|
|
|
84
86
|
* @returns {Request} Duplex 流
|
|
85
87
|
*/ function fn(verb) {
|
|
86
88
|
const method = verb.toUpperCase();
|
|
89
|
+
// @ts-ignore
|
|
87
90
|
return (uri, options, callback)=>{
|
|
88
91
|
const { opts, cb } = init(uri, options, callback);
|
|
89
92
|
opts.method = method;
|
package/lib/request.js
CHANGED
|
@@ -14,8 +14,9 @@ import ZlibTransform from './ZlibTransform.js';
|
|
|
14
14
|
import utils from './utils.js';
|
|
15
15
|
import Caseless from './caseless.js';
|
|
16
16
|
const log = Log({
|
|
17
|
-
env: `wia:req:${name(
|
|
18
|
-
})
|
|
17
|
+
env: `wia:req:${name(import.meta.url)}`
|
|
18
|
+
}) // __filename
|
|
19
|
+
;
|
|
19
20
|
const httpModules = {
|
|
20
21
|
'http:': http,
|
|
21
22
|
'https:': https
|
|
@@ -51,7 +52,7 @@ const writeEventEmit = Object.create(null);
|
|
|
51
52
|
for (const ev of writeEvents)writeEventEmit[ev] = function(...args) {
|
|
52
53
|
const m = this // 事件回调,this === clientRequest 实例
|
|
53
54
|
;
|
|
54
|
-
log
|
|
55
|
+
log('req event', {
|
|
55
56
|
ev
|
|
56
57
|
});
|
|
57
58
|
m.redirectReq.emit(ev, ...args) // req 事情映射到 redirectReq 上触发
|
|
@@ -71,7 +72,7 @@ const readEventEmit = Object.create(null);
|
|
|
71
72
|
for (const ev of readEvents)readEventEmit[ev] = function(...args) {
|
|
72
73
|
const m = this // 事件回调,this === clientRequest 实例
|
|
73
74
|
;
|
|
74
|
-
log
|
|
75
|
+
log('res event', {
|
|
75
76
|
ev
|
|
76
77
|
});
|
|
77
78
|
m.redirectReq.emit(ev, ...args) // 向上触发事件
|
|
@@ -88,18 +89,19 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
|
|
|
88
89
|
*/ export default class Request extends Duplex {
|
|
89
90
|
/**
|
|
90
91
|
* responseCallback 原消息处理回调
|
|
91
|
-
* @param {*}
|
|
92
|
+
* @param {*} opts
|
|
92
93
|
* @param {*} resCallback
|
|
93
|
-
*/ constructor(
|
|
94
|
+
*/ constructor(opts, resCallback){
|
|
94
95
|
super(), this._timeout = 0, /** @type {*} */ this.socket = null, /** @type {http.ClientRequest} */ this._currentRequest = null, /** @type {stream.Readable} */ this.response = null, /** @type {stream.Readable} */ this.responseStream = null, this.timing = false, this.responseStarted = false, this.responseStartTime = 0, this._destdata = false, this._paused = false, this._respended = false, /** @type {stream.Readable} */ this.pipesrc = null // 被 pipe 时的 src stream
|
|
95
96
|
, /** @type {stream.Writable[]} */ this.pipedests = [] // pipe dest
|
|
96
97
|
;
|
|
97
98
|
const m = this;
|
|
98
99
|
// log({options}, 'constructor');
|
|
99
100
|
// Initialize the request
|
|
100
|
-
m.
|
|
101
|
-
m.
|
|
102
|
-
m.headers =
|
|
101
|
+
m.sanitizeOptions(opts);
|
|
102
|
+
m.opt = opts;
|
|
103
|
+
m.headers = opts.headers;
|
|
104
|
+
// log({opts}, 'constructor')
|
|
103
105
|
m._ended = false;
|
|
104
106
|
m._ending = false;
|
|
105
107
|
m._redirectCount = 0;
|
|
@@ -110,9 +112,9 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
|
|
|
110
112
|
m.resCallback = resCallback;
|
|
111
113
|
// React to responses of native requests
|
|
112
114
|
// 接管 response 事件,非重定向,触发 response 事件
|
|
113
|
-
m._onResponse = (
|
|
115
|
+
m._onResponse = (res)=>{
|
|
114
116
|
try {
|
|
115
|
-
m.processResponse(
|
|
117
|
+
m.processResponse(res);
|
|
116
118
|
} catch (cause) {
|
|
117
119
|
m.emit('error', cause instanceof RedirectionError ? cause : new RedirectionError({
|
|
118
120
|
cause: cause
|
|
@@ -150,30 +152,30 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
|
|
|
150
152
|
});
|
|
151
153
|
}
|
|
152
154
|
// 流模式
|
|
153
|
-
if (
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
m.pipesrc = src;
|
|
160
|
-
if (utils.isReadStream(src)) {
|
|
161
|
-
if (!m.hasHeader('content-type')) {
|
|
162
|
-
m.setHeader('content-type', mime.lookup(src.path));
|
|
155
|
+
if (opts.stream) {
|
|
156
|
+
// 被 pipe 作为目标时触发,拷贝 src headers
|
|
157
|
+
m.on('pipe', /** @type {stream.Readable} */ (src)=>{
|
|
158
|
+
// m.ntick &&
|
|
159
|
+
if (m._currentRequest) {
|
|
160
|
+
m.emit('error', new Error('You cannot pipe to this stream after the outbound request has started.'));
|
|
163
161
|
}
|
|
164
|
-
|
|
165
|
-
if (src
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
162
|
+
m.pipesrc = src;
|
|
163
|
+
if (utils.isReadStream(src)) {
|
|
164
|
+
if (!m.hasHeader('content-type')) {
|
|
165
|
+
m.setHeader('content-type', mime.lookup(src.path));
|
|
166
|
+
}
|
|
167
|
+
} else {
|
|
168
|
+
if (src.headers) {
|
|
169
|
+
for (const h of src.headers){
|
|
170
|
+
if (!m.hasHeader(h)) {
|
|
171
|
+
m.setHeader(h, src.headers[h]);
|
|
172
|
+
}
|
|
169
173
|
}
|
|
170
174
|
}
|
|
175
|
+
if (src.opt.method && !m.opt.method) m.opt.method = src.opt.method;
|
|
171
176
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
// }
|
|
175
|
-
}
|
|
176
|
-
});
|
|
177
|
+
});
|
|
178
|
+
}
|
|
177
179
|
// Perform the first request
|
|
178
180
|
// m.request(); // 写入数据时执行,否则 pipe时无法写入header
|
|
179
181
|
}
|
|
@@ -182,9 +184,10 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
|
|
|
182
184
|
* @returns http(s) 实例
|
|
183
185
|
*/ request() {
|
|
184
186
|
let R = null;
|
|
187
|
+
const m = this;
|
|
188
|
+
const { opt } = m;
|
|
185
189
|
try {
|
|
186
|
-
|
|
187
|
-
// read stream
|
|
190
|
+
// reset read stream
|
|
188
191
|
m.response = null;
|
|
189
192
|
m.responseStarted = false;
|
|
190
193
|
m.responseStream = null;
|
|
@@ -195,29 +198,28 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
|
|
|
195
198
|
m._respended = false;
|
|
196
199
|
// m.httpModule = httpModules[protocol];
|
|
197
200
|
// Load the native protocol
|
|
198
|
-
let { protocol } =
|
|
199
|
-
const { agents } =
|
|
201
|
+
let { protocol } = opt;
|
|
202
|
+
const { agents } = opt;
|
|
200
203
|
// 代理以目的网址协议为准
|
|
201
204
|
// If specified, use the agent corresponding to the protocol
|
|
202
205
|
// (HTTP and HTTPS use different types of agents)
|
|
203
206
|
if (agents) {
|
|
204
207
|
const scheme = protocol.slice(0, -1);
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
208
|
+
opt.agent = agents[scheme];
|
|
209
|
+
// http 非隧道代理模式,模块以代理主机为准,其他以目的网址为准
|
|
210
|
+
// 代理内部会根据代理协议选择 http(s) 发起请求创建连接
|
|
211
|
+
if (protocol === 'http:' && agents.http) {
|
|
212
|
+
protocol = agents.http.proxy && !agents.http.tunnel ? agents.http.proxy.protocol : protocol;
|
|
213
|
+
}
|
|
211
214
|
}
|
|
212
215
|
const httpModule = httpModules[protocol];
|
|
213
216
|
if (!httpModule) throw TypeError(`Unsupported protocol: ${protocol}`);
|
|
214
|
-
log
|
|
215
|
-
|
|
217
|
+
log({
|
|
218
|
+
opt,
|
|
216
219
|
protocol
|
|
217
|
-
});
|
|
218
|
-
debugger;
|
|
220
|
+
}, 'request');
|
|
219
221
|
// Create the native request and set up its event handlers
|
|
220
|
-
const req = httpModule.request(
|
|
222
|
+
const req = httpModule.request(opt, m._onResponse);
|
|
221
223
|
m._currentRequest = req;
|
|
222
224
|
req.redirectReq = m;
|
|
223
225
|
// 接收req事件,转发 到 redirectReq 发射
|
|
@@ -226,7 +228,7 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
|
|
|
226
228
|
// a client MUST send only the absolute path […] as the request-target.
|
|
227
229
|
// When making a request to a proxy, […]
|
|
228
230
|
// a client MUST send the target URI in absolute-form […].
|
|
229
|
-
m._currentUrl = /^\//.test(
|
|
231
|
+
m._currentUrl = /^\//.test(opt.path) ? url.format(opt) : opt.path;
|
|
230
232
|
// End a redirected request
|
|
231
233
|
// (The first request must be ended explicitly with RedirectableRequest#end)
|
|
232
234
|
if (m._isRedirect) {
|
|
@@ -302,7 +304,7 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
|
|
|
302
304
|
return;
|
|
303
305
|
}
|
|
304
306
|
// Only write when we don't exceed the maximum body length
|
|
305
|
-
if (m._requestBodyLength + chunk.length <= m.
|
|
307
|
+
if (m._requestBodyLength + chunk.length <= m.opt.maxBodyLength) {
|
|
306
308
|
m._requestBodyLength += chunk.length;
|
|
307
309
|
m._requestBodyBuffers.push({
|
|
308
310
|
data: chunk,
|
|
@@ -351,27 +353,27 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
|
|
|
351
353
|
* @param {string} name
|
|
352
354
|
* @returns
|
|
353
355
|
*/ hasHeader(name) {
|
|
354
|
-
return this.
|
|
356
|
+
return this.opt.headers.includes(name);
|
|
355
357
|
}
|
|
356
358
|
/**
|
|
357
359
|
*
|
|
358
360
|
* @param {string} name
|
|
359
361
|
* @returns {string}
|
|
360
362
|
*/ getHeader(name) {
|
|
361
|
-
return this.
|
|
363
|
+
return this.opt.headers[name];
|
|
362
364
|
}
|
|
363
365
|
/**
|
|
364
366
|
* Sets a header value on the current native request
|
|
365
367
|
* @param {string} name
|
|
366
368
|
*/ setHeader(name, value) {
|
|
367
|
-
this.
|
|
369
|
+
this.opt.headers[name] = value;
|
|
368
370
|
this._currentRequest?.setHeader(name, value);
|
|
369
371
|
}
|
|
370
372
|
/**
|
|
371
373
|
* Clears a header value on the current native request
|
|
372
374
|
* @param {string} name
|
|
373
375
|
*/ removeHeader(name) {
|
|
374
|
-
delete this.
|
|
376
|
+
delete this.opt.headers[name];
|
|
375
377
|
this._currentRequest?.removeHeader(name);
|
|
376
378
|
}
|
|
377
379
|
/**
|
|
@@ -443,7 +445,7 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
|
|
|
443
445
|
m.on('close', clearTimer);
|
|
444
446
|
return m;
|
|
445
447
|
}
|
|
446
|
-
|
|
448
|
+
sanitizeOptions(options) {
|
|
447
449
|
// Ensure headers are always present
|
|
448
450
|
if (!options.headers) options.headers = {};
|
|
449
451
|
// Since http.request treats host as an alias of hostname,
|
|
@@ -475,7 +477,7 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
|
|
|
475
477
|
const m = this;
|
|
476
478
|
// Store the redirected response
|
|
477
479
|
const { statusCode } = response;
|
|
478
|
-
if (m.
|
|
480
|
+
if (m.opt.trackRedirects) {
|
|
479
481
|
m._redirects.push({
|
|
480
482
|
url: m._currentUrl,
|
|
481
483
|
headers: response.headers,
|
|
@@ -494,7 +496,7 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
|
|
|
494
496
|
statusCode,
|
|
495
497
|
headers: response.headers
|
|
496
498
|
});
|
|
497
|
-
if (!location || m.
|
|
499
|
+
if (!location || m.opt.followRedirects === false || statusCode < 300 || statusCode >= 400) {
|
|
498
500
|
// 非重定向,返回给原始回调处理
|
|
499
501
|
response.responseUrl = m._currentUrl;
|
|
500
502
|
response.redirects = m._redirects;
|
|
@@ -526,34 +528,34 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
|
|
|
526
528
|
response.destroy();
|
|
527
529
|
// RFC7231§6.4: A client SHOULD detect and intervene
|
|
528
530
|
// in cyclical redirections (i.e., "infinite" redirection loops).
|
|
529
|
-
if (++m._redirectCount > m.
|
|
531
|
+
if (++m._redirectCount > m.opt.maxRedirects) throw new TooManyRedirectsError();
|
|
530
532
|
// Store the request headers if applicable
|
|
531
533
|
let requestHeaders;
|
|
532
|
-
const { beforeRedirect } = m.
|
|
534
|
+
const { beforeRedirect } = m.opt;
|
|
533
535
|
if (beforeRedirect) {
|
|
534
536
|
requestHeaders = {
|
|
535
537
|
// The Host header was set by nativeProtocol.request
|
|
536
538
|
Host: response.req.getHeader('host'),
|
|
537
|
-
...m.
|
|
539
|
+
...m.opt.headers
|
|
538
540
|
};
|
|
539
541
|
}
|
|
540
542
|
// RFC7231§6.4: Automatic redirection needs to done with
|
|
541
543
|
// care for methods not known to be safe, […]
|
|
542
544
|
// RFC7231§6.4.2–3: For historical reasons, a user agent MAY change
|
|
543
545
|
// the request method from POST to GET for the subsequent request.
|
|
544
|
-
const { method } = m.
|
|
545
|
-
if ((statusCode === 301 || statusCode === 302) && m.
|
|
546
|
+
const { method } = m.opt;
|
|
547
|
+
if ((statusCode === 301 || statusCode === 302) && m.opt.method === 'POST' || // RFC7231§6.4.4: The 303 (See Other) status code indicates that
|
|
546
548
|
// the server is redirecting the user agent to a different resource […]
|
|
547
549
|
// A user agent can perform a retrieval request targeting that URI
|
|
548
550
|
// (a GET or HEAD request if using HTTP) […]
|
|
549
|
-
statusCode === 303 && !/^(?:GET|HEAD)$/.test(m.
|
|
550
|
-
m.
|
|
551
|
+
statusCode === 303 && !/^(?:GET|HEAD)$/.test(m.opt.method)) {
|
|
552
|
+
m.opt.method = 'GET';
|
|
551
553
|
// Drop a possible entity and headers related to it
|
|
552
554
|
m._requestBodyBuffers = [];
|
|
553
|
-
removeMatchingHeaders(/^content-/i, m.
|
|
555
|
+
removeMatchingHeaders(/^content-/i, m.opt.headers);
|
|
554
556
|
}
|
|
555
557
|
// Drop the Host header, as the redirect might lead to a different host
|
|
556
|
-
const currentHostHeader = removeMatchingHeaders(/^host$/i, m.
|
|
558
|
+
const currentHostHeader = removeMatchingHeaders(/^host$/i, m.opt.headers);
|
|
557
559
|
// If the redirect is relative, carry over the host of the last request
|
|
558
560
|
const currentUrlParts = utils.parseUrl(m._currentUrl);
|
|
559
561
|
const currentHost = currentHostHeader || currentUrlParts.host;
|
|
@@ -567,11 +569,11 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
|
|
|
567
569
|
}, 'redirecting to');
|
|
568
570
|
m._isRedirect = true;
|
|
569
571
|
// 覆盖原 url 解析部分,包括 protocol、hostname、port等
|
|
570
|
-
utils.spreadUrlObject(redirectUrl, m.
|
|
572
|
+
utils.spreadUrlObject(redirectUrl, m.opt);
|
|
571
573
|
// Drop confidential headers when redirecting to a less secure protocol
|
|
572
574
|
// or to a different domain that is not a superdomain
|
|
573
575
|
if (redirectUrl.protocol !== currentUrlParts.protocol && redirectUrl.protocol !== 'https:' || redirectUrl.host !== currentHost && !isSubdomain(redirectUrl.host, currentHost)) {
|
|
574
|
-
removeMatchingHeaders(/^(?:(?:proxy-)?authorization|cookie)$/i, this.
|
|
576
|
+
removeMatchingHeaders(/^(?:(?:proxy-)?authorization|cookie)$/i, this.opt.headers);
|
|
575
577
|
}
|
|
576
578
|
// Evaluate the beforeRedirect callback
|
|
577
579
|
if (utils.isFunction(beforeRedirect)) {
|
|
@@ -584,8 +586,8 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
|
|
|
584
586
|
method,
|
|
585
587
|
headers: requestHeaders
|
|
586
588
|
};
|
|
587
|
-
beforeRedirect(m.
|
|
588
|
-
m.
|
|
589
|
+
beforeRedirect(m.opt, responseDetails, requestDetails);
|
|
590
|
+
m.sanitizeOptions(m.opt);
|
|
589
591
|
}
|
|
590
592
|
// Perform the redirected request
|
|
591
593
|
m.request() // 重新执行请求
|
|
@@ -597,7 +599,7 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
|
|
|
597
599
|
* @param {*} res
|
|
598
600
|
*/ processStream(res) {
|
|
599
601
|
const m = this;
|
|
600
|
-
const {
|
|
602
|
+
const { opt: opts } = m;
|
|
601
603
|
const streams = [
|
|
602
604
|
res
|
|
603
605
|
];
|
|
@@ -746,7 +748,7 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
|
|
|
746
748
|
* @param {*} dest
|
|
747
749
|
*/ pipeDest(dest) {
|
|
748
750
|
const m = this;
|
|
749
|
-
const { response
|
|
751
|
+
const { response } = m;
|
|
750
752
|
// Called after the response is received
|
|
751
753
|
if (response?.headers && dest.headers && !dest.headersSent) {
|
|
752
754
|
const caseless = new Caseless(response.headers);
|
|
@@ -773,9 +775,9 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
|
|
|
773
775
|
}
|
|
774
776
|
dest.statusCode = response.statusCode;
|
|
775
777
|
}
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
778
|
+
if (m.pipefilter) {
|
|
779
|
+
m.pipefilter(response, dest);
|
|
780
|
+
}
|
|
779
781
|
}
|
|
780
782
|
/**
|
|
781
783
|
* 暂停read流
|