@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/lib/request.js CHANGED
@@ -33,14 +33,14 @@ const log = Log({
33
33
  * @prop {*} [beforeRedirect]
34
34
  * @prop {boolean} [followRedirects]
35
35
  * @prop {number} [maxRedirects=21]
36
- * @prop {number} [maxBodyLength = 0]
36
+ * @prop {number} [maxBodyLength = -1]
37
37
  * @prop {*} [trackRedirects]
38
38
  * @prop {*} [data]
39
39
  */ /** @typedef {object} ResponseExt
40
40
  * @prop {*[]} [redirects]
41
41
  * @prop {string} [responseUrl]
42
42
  * @prop {number} [responseStartTime]
43
- */ /** @typedef { http.IncomingMessage & ResponseExt} Response*/ const httpModules = {
43
+ */ /** @typedef { http.IncomingMessage & ResponseExt} Response */ const httpModules = {
44
44
  'http:': http,
45
45
  'https:': https
46
46
  };
@@ -90,7 +90,7 @@ const writeEvents = [
90
90
  'connect',
91
91
  'continue',
92
92
  'drain',
93
- 'error',
93
+ // 'error', // 单独处理,未注册 'error' 事件处理程序,错误将冒泡到全局导致程序崩溃
94
94
  'finish',
95
95
  'information',
96
96
  'pipe',
@@ -105,7 +105,7 @@ for (const ev of writeEvents)writeEventEmit[ev] = /** @param {...any} args */ f
105
105
  const m = this // 事件回调,this === clientRequest 实例
106
106
  ;
107
107
  // log('req event', {ev})
108
- m.redirectReq.emit(ev, ...args) // req 事情映射到 redirectReq 上触发
108
+ m.redirectReq.emit(ev, ...args) // 内部请求req 事情转发到 Request
109
109
  ;
110
110
  };
111
111
  // stream.Readable,在响应流上转发读流取事件
@@ -131,6 +131,11 @@ const RedirectionError = utils.createErrorType('ERR_FR_REDIRECTION_FAILURE', 'Re
131
131
  const TooManyRedirectsError = utils.createErrorType('ERR_FR_TOO_MANY_REDIRECTS', 'Maximum number of redirects exceeded', RedirectionError);
132
132
  const MaxBodyLengthExceededError = utils.createErrorType('ERR_FR_MAX_BODY_LENGTH_EXCEEDED', 'Request body larger than maxBodyLength limit');
133
133
  const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', 'write after end');
134
+ // request err
135
+ const HostNotfoundError = utils.createErrorType('ERR_HOSTNOTFOUND', 'DNS 解析失败,主机名可能无效');
136
+ const ConnRefusedError = utils.createErrorType('ERR_CONNREFUSED', '连接被拒绝,目标服务器可能不可用');
137
+ const ConnTimedoutError = utils.createErrorType('ERR_CONNTIMEDOUT', '请求超时,请检查网络连接或服务器负载');
138
+ const ConnResetError = utils.createErrorType('ERR_CONNRESET', '连接被重置,可能是网络问题或服务器关闭了连接');
134
139
  /**
135
140
  * An HTTP(S) request that can be redirected
136
141
  * wrap http.ClientRequest
@@ -266,7 +271,39 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
266
271
  req.redirectReq = m;
267
272
  // 启动 startTimer
268
273
  if (m.startTimer) m._currentRequest.once('socket', m.startTimer);
269
- // 接收req事件,转发 redirectReq 发射
274
+ // set tcp keep alive to prevent drop connection by peer
275
+ req.on('socket', /** @param {*} socket */ (socket)=>{
276
+ // default interval of sending ack packet is 1 minute
277
+ socket.setKeepAlive(true, 1000 * 60);
278
+ });
279
+ // 请求error单独处理
280
+ // 'error' 事件处理,避免错误将冒泡到全局导致程序崩溃
281
+ req.on('error', (err)=>{
282
+ destroyRequest(req) // 释放资源
283
+ ;
284
+ // @ts-ignore
285
+ log.error({
286
+ errcode: err?.code
287
+ }, 'request');
288
+ // @ts-ignore
289
+ switch(err?.code){
290
+ case 'ENOTFOUND':
291
+ m.emit('error', new HostNotfoundError());
292
+ break;
293
+ case 'ECONNREFUSED':
294
+ m.emit('error', new ConnRefusedError());
295
+ break;
296
+ case 'ETIMEDOUT':
297
+ m.emit('error', new ConnTimedoutError());
298
+ break;
299
+ case 'ECONNRESET':
300
+ m.emit('error', new ConnResetError());
301
+ break;
302
+ default:
303
+ m.emit('error', utils.createErrorType('ERR_CONNOTHER', `网络错误: ${err.message}`));
304
+ }
305
+ });
306
+ // 接收req事件,转发 到 request 上发射,网络关闭事件,触发 error
270
307
  for (const ev of writeEvents)req.on(ev, writeEventEmit[ev]);
271
308
  // RFC7230§5.3.1: When making a request directly to an origin server, […]
272
309
  // a client MUST send only the absolute path […] as the request-target.
@@ -302,9 +339,10 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
302
339
  }
303
340
  return R;
304
341
  }
305
- abort() {
342
+ /**
343
+ * 写入错误,释放请求,触发 abort 终止事件
344
+ */ abort() {
306
345
  destroyRequest(this._currentRequest);
307
- this._currentRequest.abort();
308
346
  this.emit('abort');
309
347
  }
310
348
  /**
@@ -359,7 +397,11 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
359
397
  const m = this;
360
398
  // log({data: chunk, encoding, cb}, 'write')
361
399
  // Writing is not allowed if end has been called
362
- if (m._ending) throw new WriteAfterEndError();
400
+ if (m._ending) {
401
+ // throw new WriteAfterEndError()
402
+ m.emit('error', new WriteAfterEndError());
403
+ return;
404
+ }
363
405
  // ! 数据写入时连接,pipe 时可设置 header
364
406
  if (!m._currentRequest) m.request();
365
407
  // Validate input and shift parameters if necessary
@@ -673,13 +715,15 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
673
715
  /**
674
716
  * 处理响应stream
675
717
  * 自动解压,透传流,需设置 decompress = false,避免解压数据
676
- * @param {*} res
718
+ * @param {Response} res
719
+ * @returns {Response | stream.Readable}
677
720
  */ processStream(res) {
678
721
  const m = this;
679
722
  const { opt } = m;
680
723
  const streams = [
681
724
  res
682
725
  ];
726
+ let responseStream = res;
683
727
  // 'transfer-encoding': 'chunked'时,无content-length,axios v1.2 不能自动解压
684
728
  const responseLength = +res.headers['content-length'];
685
729
  // log('processStream', {
@@ -707,19 +751,23 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
707
751
  case 'compress':
708
752
  case 'x-compress':
709
753
  // add the unzipper to the body stream processing pipeline
754
+ // @ts-ignore
710
755
  streams.push(zlib.createUnzip(zlibOptions));
711
756
  // remove the content-encoding in order to not confuse downstream operations
712
757
  res.headers['content-encoding'] = undefined;
713
758
  break;
714
759
  case 'deflate':
760
+ // @ts-ignore
715
761
  streams.push(new ZlibTransform());
716
762
  // add the unzipper to the body stream processing pipeline
763
+ // @ts-ignore
717
764
  streams.push(zlib.createUnzip(zlibOptions));
718
765
  // remove the content-encoding in order to not confuse downstream operations
719
766
  res.headers['content-encoding'] = undefined;
720
767
  break;
721
768
  case 'br':
722
769
  if (isBrotliSupported) {
770
+ // @ts-ignore
723
771
  streams.push(zlib.createBrotliDecompress(brotliOptions));
724
772
  res.headers['content-encoding'] = undefined;
725
773
  }
@@ -728,9 +776,12 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
728
776
  }
729
777
  }
730
778
  // 响应流,用于读
731
- const responseStream = streams.length > 1 ? stream.pipeline(streams, utils.noop) : streams[0];
779
+ // @ts-ignore
780
+ responseStream = streams.length > 1 ? stream.pipeline(streams, utils.noop) : streams[0];
732
781
  // 将内部 responseStream 可读流 映射到 redirectReq
782
+ // @ts-ignore
733
783
  m.responseStream = responseStream;
784
+ // @ts-ignore
734
785
  responseStream.redirectReq = m // 事情触发时引用
735
786
  ;
736
787
  // stream 模式,事件透传到 请求类
@@ -880,7 +931,9 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
880
931
  }
881
932
  }
882
933
  /**
883
- *
934
+ * 释放请求,触发error事件
935
+ * 'error' event, and emit a 'close' event.
936
+ * Calling this will cause remaining data in the response to be dropped and the socket to be destroyed.
884
937
  * @param {*} request
885
938
  * @param {*} error
886
939
  */ function destroyRequest(request, error) {
@@ -888,7 +941,8 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
888
941
  request.removeListener(ev, writeEventEmit[ev]);
889
942
  }
890
943
  request.on('error', utils.noop);
891
- request.destroy(error);
944
+ request.destroy(error) // 触发 error 事件
945
+ ;
892
946
  }
893
947
  /**
894
948
  *
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@wiajs/request",
3
3
  "description": "Stream HTTP request client.",
4
4
  "keywords": ["http", "simple", "util", "utility"],
5
- "version": "3.0.29",
5
+ "version": "3.0.31",
6
6
  "type": "module",
7
7
  "main": "index.js",
8
8
  "types": "types/index.d.ts",
package/types/index.d.ts CHANGED
@@ -1,14 +1,40 @@
1
1
  export default request;
2
- declare function request(uri: any, options: any, callback: any): Request;
2
+ export type Response = import("./request").Response;
3
+ export type Opts = {
4
+ headers?: {
5
+ [x: string]: string;
6
+ };
7
+ url?: string;
8
+ protocol?: "http:" | "https:";
9
+ host?: string;
10
+ family?: string;
11
+ path?: string;
12
+ method?: string;
13
+ agent?: any;
14
+ agents?: any;
15
+ body?: any;
16
+ data?: any;
17
+ stream?: boolean;
18
+ decompress?: boolean;
19
+ transformStream?: any;
20
+ beforeRedirect?: any;
21
+ followRedirects?: boolean;
22
+ maxRedirects?: number;
23
+ maxBodyLength?: number;
24
+ trackRedirects?: any;
25
+ };
26
+ export type Cb = (res: Response, stream?: stream.Readable) => void;
27
+ declare function request(uri: string | Opts, options?: Opts | Cb, callback?: Cb): Request;
3
28
  declare namespace request {
4
- export let get: Request;
5
- export let head: Request;
6
- export let options: Request;
7
- export let post: Request;
8
- export let put: Request;
9
- export let patch: Request;
10
- export let del: Request;
11
- let _delete: Request;
29
+ export let get: (url: string | Opts, opts?: Opts | Cb, cb?: Cb) => void;
30
+ export let head: (url: string | Opts, opts?: Opts | Cb, cb?: Cb) => void;
31
+ export let options: (url: string | Opts, opts?: Opts | Cb, cb?: Cb) => void;
32
+ export let post: (url: string | Opts, opts?: Opts | Cb, cb?: Cb) => void;
33
+ export let put: (url: string | Opts, opts?: Opts | Cb, cb?: Cb) => void;
34
+ export let patch: (url: string | Opts, opts?: Opts | Cb, cb?: Cb) => void;
35
+ export let del: (url: string | Opts, opts?: Opts | Cb, cb?: Cb) => void;
36
+ let _delete: (url: string | Opts, opts?: Opts | Cb, cb?: Cb) => void;
12
37
  export { _delete as delete };
13
38
  }
39
+ import stream from 'node:stream';
14
40
  import Request from './request.js';
@@ -31,7 +31,8 @@ export default class Request extends stream.Duplex {
31
31
  request(): http.ClientRequest;
32
32
  abort(): void;
33
33
  destroy(error: any): this;
34
- override write(chunk: any, encodingOrCallback?: BufferEncoding | ((error: Error | null) => void), cb?: (error: Error | null) => void): boolean;
34
+ send(): void;
35
+ override write(chunk: any, encoding?: BufferEncoding | ((error: Error | null) => void), cb?: (error: Error | null) => void): boolean;
35
36
  override end(chunk?: any, encoding?: BufferEncoding | (() => void), cb?: () => void): this;
36
37
  hasHeader(name: string): boolean;
37
38
  getHeader(name: string): string;
@@ -42,7 +43,7 @@ export default class Request extends stream.Duplex {
42
43
  sanitizeOptions(options: any): void;
43
44
  processResponse(response: Response): void;
44
45
  _isRedirect: boolean;
45
- processStream(res: any): any;
46
+ processStream(res: Response): Response | stream.Readable;
46
47
  override pipe<T>(dest: T & stream.Writable, opts?: {
47
48
  end?: boolean;
48
49
  }): T;
@@ -70,6 +71,7 @@ export type Opts = {
70
71
  maxRedirects?: number;
71
72
  maxBodyLength?: number;
72
73
  trackRedirects?: any;
74
+ data?: any;
73
75
  };
74
76
  export type ResponseExt = {
75
77
  redirects?: any[];
package/types/utils.d.ts CHANGED
@@ -11,6 +11,7 @@ declare namespace _default {
11
11
  export { isObject };
12
12
  export { isURL };
13
13
  export { isReadStream };
14
+ export { isStream };
14
15
  export { noop };
15
16
  export { parseUrl };
16
17
  export { spreadUrlObject };
@@ -38,6 +39,7 @@ declare function isFunction(thing: any): boolean;
38
39
  declare function isObject(thing: any): boolean;
39
40
  declare function isURL(value: any): boolean;
40
41
  declare function isReadStream(rs: any): any;
42
+ declare function isStream(val: any): boolean;
41
43
  declare function noop(): void;
42
44
  declare function parseUrl(input: any): any;
43
45
  declare function spreadUrlObject(urlObject: any, target: any): any;