@wiajs/request 3.0.28 → 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/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,37 @@ 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
+ log.error({
285
+ errcode: err.code
286
+ }, 'request');
287
+ switch(err.code){
288
+ case 'ENOTFOUND':
289
+ m.emit('error', new HostNotfoundError());
290
+ break;
291
+ case 'ECONNREFUSED':
292
+ m.emit('error', new ConnRefusedError());
293
+ break;
294
+ case 'ETIMEDOUT':
295
+ m.emit('error', new ConnTimedoutError());
296
+ break;
297
+ case 'ECONNRESET':
298
+ m.emit('error', new ConnResetError());
299
+ break;
300
+ default:
301
+ m.emit('error', utils.createErrorType('ERR_CONNOTHER', `网络错误: ${err.message}`));
302
+ }
303
+ });
304
+ // 接收req事件,转发 到 request 上发射,网络关闭事件,触发 error
270
305
  for (const ev of writeEvents)req.on(ev, writeEventEmit[ev]);
271
306
  // RFC7230§5.3.1: When making a request directly to an origin server, […]
272
307
  // a client MUST send only the absolute path […] as the request-target.
@@ -302,9 +337,10 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
302
337
  }
303
338
  return R;
304
339
  }
305
- abort() {
340
+ /**
341
+ * 写入错误,释放请求,触发 abort 终止事件
342
+ */ abort() {
306
343
  destroyRequest(this._currentRequest);
307
- this._currentRequest.abort();
308
344
  this.emit('abort');
309
345
  }
310
346
  /**
@@ -359,7 +395,11 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
359
395
  const m = this;
360
396
  // log({data: chunk, encoding, cb}, 'write')
361
397
  // Writing is not allowed if end has been called
362
- if (m._ending) throw new WriteAfterEndError();
398
+ if (m._ending) {
399
+ // throw new WriteAfterEndError()
400
+ m.emit('error', new WriteAfterEndError());
401
+ return;
402
+ }
363
403
  // ! 数据写入时连接,pipe 时可设置 header
364
404
  if (!m._currentRequest) m.request();
365
405
  // Validate input and shift parameters if necessary
@@ -673,13 +713,15 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
673
713
  /**
674
714
  * 处理响应stream
675
715
  * 自动解压,透传流,需设置 decompress = false,避免解压数据
676
- * @param {*} res
716
+ * @param {Response} res
717
+ * @returns {Response | stream.Readable}
677
718
  */ processStream(res) {
678
719
  const m = this;
679
720
  const { opt } = m;
680
721
  const streams = [
681
722
  res
682
723
  ];
724
+ let responseStream = res;
683
725
  // 'transfer-encoding': 'chunked'时,无content-length,axios v1.2 不能自动解压
684
726
  const responseLength = +res.headers['content-length'];
685
727
  // log('processStream', {
@@ -707,19 +749,23 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
707
749
  case 'compress':
708
750
  case 'x-compress':
709
751
  // add the unzipper to the body stream processing pipeline
752
+ // @ts-ignore
710
753
  streams.push(zlib.createUnzip(zlibOptions));
711
754
  // remove the content-encoding in order to not confuse downstream operations
712
755
  res.headers['content-encoding'] = undefined;
713
756
  break;
714
757
  case 'deflate':
758
+ // @ts-ignore
715
759
  streams.push(new ZlibTransform());
716
760
  // add the unzipper to the body stream processing pipeline
761
+ // @ts-ignore
717
762
  streams.push(zlib.createUnzip(zlibOptions));
718
763
  // remove the content-encoding in order to not confuse downstream operations
719
764
  res.headers['content-encoding'] = undefined;
720
765
  break;
721
766
  case 'br':
722
767
  if (isBrotliSupported) {
768
+ // @ts-ignore
723
769
  streams.push(zlib.createBrotliDecompress(brotliOptions));
724
770
  res.headers['content-encoding'] = undefined;
725
771
  }
@@ -728,9 +774,12 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
728
774
  }
729
775
  }
730
776
  // 响应流,用于读
731
- const responseStream = streams.length > 1 ? stream.pipeline(streams, utils.noop) : streams[0];
777
+ // @ts-ignore
778
+ responseStream = streams.length > 1 ? stream.pipeline(streams, utils.noop) : streams[0];
732
779
  // 将内部 responseStream 可读流 映射到 redirectReq
780
+ // @ts-ignore
733
781
  m.responseStream = responseStream;
782
+ // @ts-ignore
734
783
  responseStream.redirectReq = m // 事情触发时引用
735
784
  ;
736
785
  // stream 模式,事件透传到 请求类
@@ -880,7 +929,9 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
880
929
  }
881
930
  }
882
931
  /**
883
- *
932
+ * 释放请求,触发error事件
933
+ * 'error' event, and emit a 'close' event.
934
+ * Calling this will cause remaining data in the response to be dropped and the socket to be destroyed.
884
935
  * @param {*} request
885
936
  * @param {*} error
886
937
  */ function destroyRequest(request, error) {
@@ -888,7 +939,8 @@ const WriteAfterEndError = utils.createErrorType('ERR_STREAM_WRITE_AFTER_END', '
888
939
  request.removeListener(ev, writeEventEmit[ev]);
889
940
  }
890
941
  request.on('error', utils.noop);
891
- request.destroy(error);
942
+ request.destroy(error) // 触发 error 事件
943
+ ;
892
944
  }
893
945
  /**
894
946
  *
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.28",
5
+ "version": "3.0.30",
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;