@zwa73/utils 1.0.231 → 1.0.233

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.
@@ -2,7 +2,6 @@ import { AnyString, JToken, MPromise, PartialOption, StatusVerifyFn } from "./Ut
2
2
  import http from 'http';
3
3
  import { PromiseRetries } from "./UtilFunctions";
4
4
  import FormData from "form-data";
5
- import { RequiredOnly } from "@zwa73/js-utils";
6
5
  /**网络请求返回值 */
7
6
  export type RequestResult<T> = {
8
7
  /**响应头 */
@@ -39,34 +38,47 @@ export type RequestOption = {
39
38
  /**getquery请求所允许的数据 */
40
39
  export type QueryRequestData = NodeJS.Dict<string | number | boolean | readonly string[] | readonly number[] | readonly boolean[] | null>;
41
40
  /**请求处理函数 需调用req.end() */
42
- export type RequestProcFn = ((req: http.ClientRequest) => MPromise<void>);
41
+ export type RequestProcFn = (req: http.ClientRequest) => MPromise<void>;
42
+ /**结果处理函数 */
43
+ export type RequestParseFn<D, R> = (result: RequestResult<D> | undefined) => MPromise<R>;
43
44
  /**数据处理函数 */
44
45
  export type RequestReduceFn<T> = (acc: T, data: string) => MPromise<T>;
46
+ /**数据初始化函数 */
47
+ export type RequestInitFn<T> = (res: http.IncomingMessage) => MPromise<T>;
45
48
  declare const AcceptTypeList: readonly ["json", "string"];
46
49
  /**可用的接受类型 */
47
50
  type AcceptType = typeof AcceptTypeList[number];
48
51
  declare const SendTypeList: readonly ["json", "query", "formData", "none"];
49
52
  /**可用的发送类型 */
50
53
  type SendType = typeof SendTypeList[number];
51
- /**accept处理数据 */
52
- type AcceptProc<D, T> = {
53
- init: D;
54
+ /**accept处理数据
55
+ * @template D - 接受时转换的数据类型
56
+ * @template R - 完成处理的数据类型
57
+ */
58
+ type AcceptProcCtor<D, R, T> = (arg: T) => MPromise<AcceptProc<D, R>>;
59
+ type AcceptProc<D, R> = {
60
+ init: RequestInitFn<D>;
54
61
  reduce: RequestReduceFn<D>;
55
- parse: (result: RequestResult<D> | undefined) => MPromise<T>;
62
+ parse: RequestParseFn<D, R>;
56
63
  };
57
64
  /**send处理数据 */
58
- type SendProc<T extends any[]> = {
59
- proc: (opt: RequestOption, ...args: T) => MPromise<RequestProcFn>;
65
+ type SendProcCtor<T extends {}> = (opt: RequestOption, arg: T) => MPromise<SendProc>;
66
+ type SendProc = {
67
+ proc: RequestProcFn;
60
68
  };
61
- declare const SendNoneProc: SendProc<[]>;
62
- declare const AcceptStringProc: AcceptProc<string, RequestResult<string> | undefined>;
63
- declare const AcceptNoneProc: AcceptProc<undefined, undefined>;
69
+ declare const SendNoneProc: SendProcCtor<{}>;
70
+ declare const AcceptStringProc: AcceptProcCtor<string, RequestResult<string> | undefined, {}>;
71
+ declare const AcceptNoneProc: AcceptProcCtor<undefined, undefined, {}>;
64
72
  /**send处理的参数 */
65
- type SendParams<P extends SendProc<any>> = P extends SendProc<infer T> ? T : never;
73
+ type SendParams<S extends SendProcCtor<any>> = S extends SendProcCtor<infer P> ? P : never;
74
+ /**send处理的参数 */
75
+ type AcceptParams<A extends AcceptProcCtor<any, any, any>> = A extends AcceptProcCtor<any, any, infer P> ? P : never;
76
+ type HasConflict<A, B> = keyof A & keyof B extends never ? false : true;
77
+ type ConflictCheck<A, B, C> = HasConflict<A, B> extends true ? A & B & C & Error & "❌ A 与 B 有字段冲突" : HasConflict<A, C> extends true ? A & B & C & Error & "❌ A 与 C 有字段冲突" : HasConflict<B, C> extends true ? A & B & C & Error & "❌ B 与 C 有字段冲突" : A & B & C;
66
78
  /**accept处理的结果 */
67
- type ParseResult<P extends AcceptProc<any, any>> = P extends AcceptProc<any, infer T> ? Awaited<T> : never;
79
+ type ParseResult<P extends AcceptProcCtor<any, any, any>> = P extends AcceptProcCtor<any, infer T, any> ? Awaited<T> : never;
68
80
  /**http请求工具 */
69
- export declare class UtilHttp<D extends Partial<RequestOption> & Required<Pick<RequestOption, 'protocol'>>, S extends SendProc<any>, A extends AcceptProc<any, any>> {
81
+ export declare class UtilHttp<D extends Partial<RequestOption> & Required<Pick<RequestOption, 'protocol'>>, S extends SendProcCtor<any>, A extends AcceptProcCtor<any, any, any>> {
70
82
  private _data;
71
83
  private _send;
72
84
  private _accept;
@@ -74,11 +86,11 @@ export declare class UtilHttp<D extends Partial<RequestOption> & Required<Pick<R
74
86
  /**设为https请求 */
75
87
  static https(): UtilHttp<{
76
88
  readonly protocol: "https:";
77
- }, SendProc<[]>, AcceptProc<string, RequestResult<string> | undefined>>;
89
+ }, SendProcCtor<{}>, AcceptProcCtor<string, RequestResult<string> | undefined, {}>>;
78
90
  /**设为http请求 */
79
91
  static http(): UtilHttp<{
80
92
  readonly protocol: "http:";
81
- }, SendProc<[]>, AcceptProc<string, RequestResult<string> | undefined>>;
93
+ }, SendProcCtor<{}>, AcceptProcCtor<string, RequestResult<string> | undefined, {}>>;
82
94
  /**从url创建 */
83
95
  static url(urlStr: `${'http:' | 'https:'}//${string}`): UtilHttp<{
84
96
  protocol: "http:" | "https:";
@@ -86,7 +98,7 @@ export declare class UtilHttp<D extends Partial<RequestOption> & Required<Pick<R
86
98
  hostname: string;
87
99
  path: string;
88
100
  port: number | undefined;
89
- }, SendProc<[]>, AcceptProc<string, RequestResult<string> | undefined>>;
101
+ }, SendProcCtor<{}>, AcceptProcCtor<string, RequestResult<string> | undefined, {}>>;
90
102
  /**设为get方式的请求 */
91
103
  get(): UtilHttp<D & {
92
104
  method: "GET";
@@ -100,11 +112,6 @@ export declare class UtilHttp<D extends Partial<RequestOption> & Required<Pick<R
100
112
  * 将会替换对应字段, 修改headers请用header函数
101
113
  */
102
114
  option<OPT extends Partial<RequestOption>>(option: OPT): UtilHttp<D & OPT, S, A>;
103
- /**完成参数
104
- * 会检查必要参数完整性
105
- * 将会替换对应字段, 修改headers请用header函数
106
- */
107
- finalize<OPT extends PartialOption<RequestOption, D>>(option: OPT): UtilHttp<D & OPT, S, A>;
108
115
  /**补充header */
109
116
  header<HAD extends http.OutgoingHttpHeaders>(headers: HAD): UtilHttp<D & {
110
117
  headers: HAD;
@@ -120,7 +127,10 @@ export declare class UtilHttp<D extends Partial<RequestOption> & Required<Pick<R
120
127
  headers: {
121
128
  "Content-Type": "application/json";
122
129
  };
123
- }, SendProc<[JToken]>, AcceptProc<string, RequestResult<JToken> | undefined>>;
130
+ }, SendProcCtor<{
131
+ /**发送的json */
132
+ json: JToken;
133
+ }>, AcceptProcCtor<string, RequestResult<JToken> | undefined, {}>>;
124
134
  /**收发皆为json的post预设 */
125
135
  postJson(): UtilHttp<D & {
126
136
  method: "POST";
@@ -128,15 +138,21 @@ export declare class UtilHttp<D extends Partial<RequestOption> & Required<Pick<R
128
138
  headers: {
129
139
  'Content-Type': "application/json";
130
140
  };
131
- }, SendProc<[JToken]>, AcceptProc<string, RequestResult<JToken> | undefined>>;
141
+ }, SendProcCtor<{
142
+ /**发送的json */
143
+ json: JToken;
144
+ }>, AcceptProcCtor<string, RequestResult<JToken> | undefined, {}>>;
132
145
  /**无查询参数获取json的get预设 */
133
146
  getJson(): UtilHttp<D & {
134
147
  method: "GET";
135
- }, SendProc<[]>, AcceptProc<string, RequestResult<JToken> | undefined>>;
148
+ }, SendProcCtor<{}>, AcceptProcCtor<string, RequestResult<JToken> | undefined, {}>>;
136
149
  /**有查询参数获取json的get预设 */
137
150
  queryJson(): UtilHttp<D & {
138
151
  method: "GET";
139
- }, SendProc<[QueryRequestData]>, AcceptProc<string, RequestResult<JToken> | undefined>>;
152
+ }, SendProcCtor<{
153
+ /**附加的查询表单数据 */
154
+ query: QueryRequestData;
155
+ }>, AcceptProcCtor<string, RequestResult<JToken> | undefined, {}>>;
140
156
  /**收发皆为json的https-post预设 */
141
157
  static httpsPostJson(): UtilHttp<{
142
158
  readonly protocol: "https:";
@@ -146,7 +162,10 @@ export declare class UtilHttp<D extends Partial<RequestOption> & Required<Pick<R
146
162
  headers: {
147
163
  'Content-Type': "application/json";
148
164
  };
149
- }, SendProc<[JToken]>, AcceptProc<string, RequestResult<JToken> | undefined>>;
165
+ }, SendProcCtor<{
166
+ /**发送的json */
167
+ json: JToken;
168
+ }>, AcceptProcCtor<string, RequestResult<JToken> | undefined, {}>>;
150
169
  /**收发皆为json的http-post预设 */
151
170
  static httpPostJson(): UtilHttp<{
152
171
  readonly protocol: "http:";
@@ -156,66 +175,104 @@ export declare class UtilHttp<D extends Partial<RequestOption> & Required<Pick<R
156
175
  headers: {
157
176
  'Content-Type': "application/json";
158
177
  };
159
- }, SendProc<[JToken]>, AcceptProc<string, RequestResult<JToken> | undefined>>;
178
+ }, SendProcCtor<{
179
+ /**发送的json */
180
+ json: JToken;
181
+ }>, AcceptProcCtor<string, RequestResult<JToken> | undefined, {}>>;
160
182
  /**无查询参数获取json的https-get预设 */
161
183
  static httpsGetJson(): UtilHttp<{
162
184
  readonly protocol: "https:";
163
185
  } & {
164
186
  method: "GET";
165
- }, SendProc<[]>, AcceptProc<string, RequestResult<JToken> | undefined>>;
187
+ }, SendProcCtor<{}>, AcceptProcCtor<string, RequestResult<JToken> | undefined, {}>>;
166
188
  /**有查询参数获取json的https-get预设 */
167
189
  static httpsQueryJson(): UtilHttp<{
168
190
  readonly protocol: "http:";
169
191
  } & {
170
192
  method: "GET";
171
- }, SendProc<[QueryRequestData]>, AcceptProc<string, RequestResult<JToken> | undefined>>;
193
+ }, SendProcCtor<{
194
+ /**附加的查询表单数据 */
195
+ query: QueryRequestData;
196
+ }>, AcceptProcCtor<string, RequestResult<JToken> | undefined, {}>>;
172
197
  /**无查询参数获取json的http-get预设 */
173
198
  static httpGetJson(): UtilHttp<{
174
199
  readonly protocol: "http:";
175
200
  } & {
176
201
  method: "GET";
177
- }, SendProc<[]>, AcceptProc<string, RequestResult<JToken> | undefined>>;
202
+ }, SendProcCtor<{}>, AcceptProcCtor<string, RequestResult<JToken> | undefined, {}>>;
178
203
  /**有查询参数获取json的http-get预设 */
179
204
  static httpQueryJson(): UtilHttp<{
180
205
  readonly protocol: "http:";
181
206
  } & {
182
207
  method: "GET";
183
- }, SendProc<[QueryRequestData]>, AcceptProc<string, RequestResult<JToken> | undefined>>;
208
+ }, SendProcCtor<{
209
+ /**附加的查询表单数据 */
210
+ query: QueryRequestData;
211
+ }>, AcceptProcCtor<string, RequestResult<JToken> | undefined, {}>>;
184
212
  /**预设的接收数据类型*/
185
213
  accept<T extends AcceptType>(t: T): {
186
- readonly json: UtilHttp<D, S, AcceptProc<string, RequestResult<JToken> | undefined>>;
187
- readonly string: UtilHttp<D, S, AcceptProc<string, RequestResult<string> | undefined>>;
188
- readonly none: UtilHttp<D, S, AcceptProc<undefined, undefined>>;
214
+ readonly json: UtilHttp<D, S, AcceptProcCtor<string, RequestResult<JToken> | undefined, {}>>;
215
+ readonly string: UtilHttp<D, S, AcceptProcCtor<string, RequestResult<string> | undefined, {}>>;
216
+ readonly none: UtilHttp<D, S, AcceptProcCtor<undefined, undefined, {}>>;
189
217
  }[T];
190
- acceptJson(): UtilHttp<D, S, AcceptProc<string, RequestResult<JToken> | undefined>>;
218
+ acceptJson(): UtilHttp<D, S, AcceptProcCtor<string, RequestResult<JToken> | undefined, {}>>;
191
219
  acceptString(): UtilHttp<D, S, typeof AcceptStringProc>;
192
220
  acceptNone(): UtilHttp<D, S, typeof AcceptNoneProc>;
221
+ acceptFile(): UtilHttp<D, S, AcceptProcCtor<{
222
+ promise: Promise<boolean>;
223
+ }, {
224
+ /**响应头 */
225
+ headers: http.IncomingHttpHeaders;
226
+ /**响应状态码 */
227
+ statusCode?: number;
228
+ /**保存文件路径 */
229
+ filepath: string;
230
+ } | undefined, {
231
+ acceptFilepath: string;
232
+ }>>;
193
233
  /**自定的接收数据类型*/
194
- acceptRaw<AD, AT>(proc: AcceptProc<AD, AT>): UtilHttp<D, S, typeof proc>;
234
+ acceptRaw<AD, AR, AT>(proc: AcceptProcCtor<AD, AR, AT>): UtilHttp<D, S, typeof proc>;
195
235
  /**预设的发送数据类型 */
196
236
  send<T extends SendType>(t: T): {
197
237
  readonly json: UtilHttp<D & {
198
238
  headers: {
199
239
  "Content-Type": "application/json";
200
240
  };
201
- }, SendProc<[JToken]>, A>;
202
- readonly query: UtilHttp<D, SendProc<[QueryRequestData]>, A>;
241
+ }, SendProcCtor<{
242
+ /**发送的json */
243
+ json: JToken;
244
+ }>, A>;
245
+ readonly query: UtilHttp<D, SendProcCtor<{
246
+ /**附加的查询表单数据 */
247
+ query: QueryRequestData;
248
+ }>, A>;
203
249
  readonly formData: UtilHttp<D & {
204
250
  headers: {
205
251
  "Content-Type": "multipart/form-data";
206
252
  };
207
- }, SendProc<[FormData]>, A>;
253
+ }, SendProcCtor<{
254
+ /**form-data包提供的FormData表单数据 */
255
+ formdata: FormData;
256
+ }>, A>;
208
257
  readonly form: UtilHttp<D & {
209
258
  headers: {
210
259
  "Content-Type": "application/x-www-form-urlencoded";
211
260
  };
212
- }, SendProc<[QueryRequestData]>, A>;
261
+ }, SendProcCtor<{
262
+ /**表单 */
263
+ form: QueryRequestData;
264
+ }>, A>;
213
265
  readonly file: UtilHttp<D & {
214
266
  headers: {
215
267
  "Content-Type": "multipart/form-data";
216
268
  };
217
- }, SendProc<[string, (string | undefined)?]>, A>;
218
- readonly none: UtilHttp<D, SendProc<[]>, A>;
269
+ }, SendProcCtor<{
270
+ /**文件路径 */
271
+ filepath: string;
272
+ /**文件名 */
273
+ filename?: string;
274
+ }>, A>;
275
+ readonly none: UtilHttp<D, SendProcCtor<{}>, A>;
219
276
  }[T];
220
277
  /**发送json
221
278
  * 请求参数为 (token:JToken)
@@ -224,58 +281,74 @@ export declare class UtilHttp<D extends Partial<RequestOption> & Required<Pick<R
224
281
  headers: {
225
282
  "Content-Type": "application/json";
226
283
  };
227
- }, SendProc<[JToken]>, A>;
228
- /**利用 appendQuery 直接将数据附加在path上发送请求
229
- * 请求参数为 (form:QueryRequestData)
230
- */
231
- sendQuery(): UtilHttp<D, SendProc<[QueryRequestData]>, A>;
232
- /**发送表单数据
233
- * 请求参数为 (formData: FormData)
234
- */
284
+ }, SendProcCtor<{
285
+ /**发送的json */
286
+ json: JToken;
287
+ }>, A>;
288
+ /**利用 appendQuery 直接将数据附加在path上发送请求 */
289
+ sendQuery(): UtilHttp<D, SendProcCtor<{
290
+ /**附加的查询表单数据 */
291
+ query: QueryRequestData;
292
+ }>, A>;
293
+ /**发送表单数据 */
235
294
  sendFormData(): UtilHttp<D & {
236
295
  headers: {
237
296
  "Content-Type": "multipart/form-data";
238
297
  };
239
- }, SendProc<[FormData]>, A>;
240
- /**发送表单
241
- * 请求参数为 (form:QueryRequestData)
242
- */
298
+ }, SendProcCtor<{
299
+ /**form-data包提供的FormData表单数据 */
300
+ formdata: FormData;
301
+ }>, A>;
302
+ /**发送表单 */
243
303
  sendForm(): UtilHttp<D & {
244
304
  headers: {
245
305
  "Content-Type": "application/x-www-form-urlencoded";
246
306
  };
247
- }, SendProc<[QueryRequestData]>, A>;
248
- /**发送文件
249
- * 请求参数为 (filepath:string, filename?: string)
250
- */
307
+ }, SendProcCtor<{
308
+ /**表单 */
309
+ form: QueryRequestData;
310
+ }>, A>;
311
+ /**发送文件 */
251
312
  sendFile(): UtilHttp<D & {
252
313
  headers: {
253
314
  "Content-Type": "multipart/form-data";
254
315
  };
255
- }, SendProc<[string, (string | undefined)?]>, A>;
316
+ }, SendProcCtor<{
317
+ /**文件路径 */
318
+ filepath: string;
319
+ /**文件名 */
320
+ filename?: string;
321
+ }>, A>;
256
322
  sendNone(): UtilHttp<D, typeof SendNoneProc, A>;
257
323
  /**自定的发送数据类型 */
258
- sendRaw<T extends any[]>(proc: SendProc<T>): UtilHttp<D, typeof proc, A>;
324
+ sendRaw<T extends any[]>(proc: SendProcCtor<T>): UtilHttp<D, typeof proc, A>;
259
325
  /**发送请求
260
326
  * @param datas - 数据对象
261
327
  */
262
- once(...datas: {} extends RequiredOnly<PartialOption<RequestOption, D>> ? SendParams<S> : [Error & "RequestOption不完整, 请使用 finalize 完成必要项"]): Promise<ParseResult<A>>;
328
+ once<OPT extends PartialOption<RequestOption, D>>(arg: ConflictCheck<SendParams<S>, AcceptParams<A>, ({} extends OPT ? {
329
+ option?: OPT;
330
+ } : {
331
+ option: OPT;
332
+ })>): Promise<ParseResult<A>>;
263
333
  /**重复发送网络请求
264
334
  * @param verify - 有效性验证函数
265
335
  * @param retries - 重试选项 默认 延迟:1000ms 间隔:180_000ms 重试:3次
266
336
  * @param datas - 数据对象
267
337
  */
268
- retry(opt: {
338
+ retry<OPT extends PartialOption<RequestOption, D>>(arg: ConflictCheck<SendParams<S>, AcceptParams<A>, {
269
339
  verify?: StatusVerifyFn<ParseResult<A>>;
270
340
  retries?: PromiseRetries;
271
- }, ...datas: {} extends RequiredOnly<PartialOption<RequestOption, D>> ? SendParams<S> : [Error & "RequestOption不完整, 请使用 finalize 完成必要项"]): Promise<import("@zwa73/js-utils").PromiseRetryResult<ParseResult<A>>>;
341
+ } & ({} extends OPT ? {
342
+ option?: OPT;
343
+ } : {
344
+ option: OPT;
345
+ })>): Promise<import("@zwa73/js-utils").PromiseRetryResult<ParseResult<A>>>;
272
346
  /**发送网络请求
273
- * @param option - 网络请求选项
274
- * @param proc - 请求处理函数 需调用req.end()
275
- * @param reduce - 数据处理函数
276
- * @param init - 初始数据
347
+ * @param option - 网络请求选项
348
+ * @param reqProc - 请求处理函数 需调用req.end()
349
+ * @param acceptProc - 响应处理数据
277
350
  */
278
- static request<T>(option: RequestOption, proc: RequestProcFn, reduce: RequestReduceFn<T>, init: T): Promise<RequestResult<T> | undefined>;
351
+ static request<T>(option: RequestOption, sendProc: SendProc, acceptProc: Omit<AcceptProc<T, unknown>, 'parse'>): Promise<RequestResult<T> | undefined>;
279
352
  /**构建query */
280
353
  static buildQuery(base: string, data: QueryRequestData): string;
281
354
  }
package/dist/UtilHttp.js CHANGED
@@ -18,19 +18,19 @@ const fs_1 = __importDefault(require("fs"));
18
18
  const pathe_1 = __importDefault(require("pathe"));
19
19
  const AcceptTypeList = ["json", "string"];
20
20
  const SendTypeList = ["json", "query", "formData", "none"];
21
- const SendNoneProc = {
22
- proc: (opt) => (req) => void req.end()
23
- };
24
- const AcceptStringProc = {
25
- init: '',
21
+ const SendNoneProc = () => ({
22
+ proc: req => void req.end()
23
+ });
24
+ const AcceptStringProc = () => ({
25
+ init: () => '',
26
26
  reduce: (acc, dat) => acc + dat,
27
27
  parse: (result) => result
28
- };
29
- const AcceptNoneProc = {
30
- init: undefined,
28
+ });
29
+ const AcceptNoneProc = () => ({
30
+ init: () => undefined,
31
31
  reduce: () => undefined,
32
32
  parse: () => undefined
33
- };
33
+ });
34
34
  /**http请求工具 */
35
35
  class UtilHttp {
36
36
  _data;
@@ -80,14 +80,6 @@ class UtilHttp {
80
80
  this._data = { ...this._data, ...option };
81
81
  return this;
82
82
  }
83
- /**完成参数
84
- * 会检查必要参数完整性
85
- * 将会替换对应字段, 修改headers请用header函数
86
- */
87
- finalize(option) {
88
- this._data = { ...this._data, ...option };
89
- return this;
90
- }
91
83
  /**补充header */
92
84
  header(headers) {
93
85
  this._data.headers = {
@@ -167,10 +159,10 @@ class UtilHttp {
167
159
  return map[t];
168
160
  }
169
161
  acceptJson() {
170
- const proc = {
171
- init: '',
162
+ const acceptProc = () => ({
163
+ init: () => '',
172
164
  reduce: (acc, curr) => acc + curr,
173
- parse: (result) => {
165
+ parse: result => {
174
166
  if (result == undefined) {
175
167
  UtilLogger_1.SLogger.warn(`json accept 接收反馈错误: 响应结果无效`);
176
168
  return undefined;
@@ -185,13 +177,13 @@ class UtilHttp {
185
177
  UtilLogger_1.SLogger.http(`json accept 接受信息 data:`, UtilFunctions_1.UtilFunc.stringifyJToken(obj, { compress: true, space: 2 }), `result:`, UtilFunctions_1.UtilFunc.stringifyJToken(rest, { compress: true, space: 2 }));
186
178
  return { ...rest, data: obj };
187
179
  }
188
- catch (e) {
189
- UtilLogger_1.SLogger.warn(`json accept 接收反馈错误:${e}`, UtilFunctions_1.UtilFunc.stringifyJToken(result, { compress: true, space: 2 }));
180
+ catch (err) {
181
+ UtilLogger_1.SLogger.warn(`json accept 接收反馈错误:`, err, UtilFunctions_1.UtilFunc.stringifyJToken(result, { compress: true, space: 2 }));
190
182
  return { ...result, raw: data, data: null };
191
183
  }
192
184
  }
193
- };
194
- this._accept = proc;
185
+ });
186
+ this._accept = acceptProc;
195
187
  return this;
196
188
  }
197
189
  acceptString() {
@@ -202,6 +194,35 @@ class UtilHttp {
202
194
  this._accept = AcceptNoneProc;
203
195
  return this;
204
196
  }
197
+ acceptFile() {
198
+ const acceptProc = (arg) => ({
199
+ init: res => {
200
+ const fileStream = fs_1.default.createWriteStream(arg.acceptFilepath);
201
+ const fileWritePromise = new Promise((resolve) => {
202
+ fileStream.on('error', err => {
203
+ UtilLogger_1.SLogger.warn(`file accept 文件流写入错误:`, err);
204
+ resolve(false); // 标记写入已结束, 但失败
205
+ });
206
+ fileStream.on('finish', () => {
207
+ resolve(true); // 标记写入成功
208
+ });
209
+ });
210
+ res.pipe(fileStream);
211
+ return { promise: fileWritePromise };
212
+ },
213
+ reduce: acc => acc,
214
+ parse: async (result) => {
215
+ if (result == undefined)
216
+ return undefined;
217
+ const success = await result.data.promise;
218
+ if (!success)
219
+ return undefined;
220
+ return { ...result, filepath: arg.acceptFilepath };
221
+ }
222
+ });
223
+ this._accept = acceptProc;
224
+ return this;
225
+ }
205
226
  /**自定的接收数据类型*/
206
227
  acceptRaw(proc) {
207
228
  this._accept = proc;
@@ -225,97 +246,85 @@ class UtilHttp {
225
246
  * 请求参数为 (token:JToken)
226
247
  */
227
248
  sendJson() {
228
- const proc = {
229
- proc: (opt, token) => {
230
- const { method } = opt;
231
- const isPost = (method == "POST");
232
- const data = JSON.stringify(token);
233
- this._data.headers ??= {};
234
- this._data.headers['Content-Length'] = Buffer.byteLength(data);
235
- const procReq = (req) => {
249
+ const sendProc = (opt, arg) => {
250
+ const { method } = opt;
251
+ const isPost = (method == "POST");
252
+ const data = JSON.stringify(arg.json);
253
+ this._data.headers ??= {};
254
+ this._data.headers['Content-Length'] = Buffer.byteLength(data);
255
+ return {
256
+ proc: (req) => {
236
257
  if (isPost)
237
258
  req.write(data);
238
259
  req.end();
239
- };
240
- return procReq;
241
- }
260
+ }
261
+ };
242
262
  };
243
- this._send = proc;
263
+ this._send = sendProc;
244
264
  this._data.headers ??= {};
245
265
  this._data.headers['Content-Type'] = 'application/json';
246
266
  return this;
247
267
  }
248
- /**利用 appendQuery 直接将数据附加在path上发送请求
249
- * 请求参数为 (form:QueryRequestData)
250
- */
268
+ /**利用 appendQuery 直接将数据附加在path上发送请求 */
251
269
  sendQuery() {
252
- const proc = {
253
- proc: (opt, form) => {
254
- opt.path = UtilHttp.buildQuery(opt.path ?? '', form);
255
- const procReq = (req) => void req.end();
256
- return procReq;
257
- }
270
+ const sendProc = (opt, arg) => {
271
+ opt.path = UtilHttp.buildQuery(opt.path ?? '', arg.query);
272
+ return {
273
+ proc: (req) => void req.end()
274
+ };
258
275
  };
259
- this._send = proc;
276
+ this._send = sendProc;
260
277
  return this;
261
278
  }
262
- /**发送表单数据
263
- * 请求参数为 (formData: FormData)
264
- */
279
+ /**发送表单数据 */
265
280
  sendFormData() {
266
- const proc = {
267
- proc: (opt, formData) => {
268
- opt.headers = formData.getHeaders();
269
- const procReq = (req) => {
270
- formData.pipe(req);
271
- };
272
- return procReq;
273
- },
281
+ const sendProc = (opt, arg) => {
282
+ opt.headers = arg.formdata.getHeaders();
283
+ return {
284
+ proc: (req) => {
285
+ arg.formdata.pipe(req);
286
+ }
287
+ };
274
288
  };
275
- this._send = proc;
289
+ this._send = sendProc;
276
290
  this._data.headers ??= {};
277
291
  this._data.headers['Content-Type'] = 'multipart/form-data';
278
292
  return this;
279
293
  }
280
- /**发送表单
281
- * 请求参数为 (form:QueryRequestData)
282
- */
294
+ /**发送表单 */
283
295
  sendForm() {
284
- const proc = {
285
- proc: (opt, form) => {
286
- const { method } = opt;
287
- const isPost = (method == "POST");
288
- const data = querystring_1.default.stringify(form);
289
- this._data.headers ??= {};
290
- this._data.headers['Content-Length'] = Buffer.byteLength(data);
291
- const procReq = (req) => {
296
+ const snedProc = (opt, arg) => {
297
+ const { method } = opt;
298
+ const isPost = (method == "POST");
299
+ const data = querystring_1.default.stringify(arg.form);
300
+ this._data.headers ??= {};
301
+ this._data.headers['Content-Length'] = Buffer.byteLength(data);
302
+ return {
303
+ proc: (req) => {
292
304
  if (isPost)
293
305
  req.write(data);
294
306
  req.end();
295
- };
296
- return procReq;
297
- }
307
+ }
308
+ };
298
309
  };
299
- this._send = proc;
310
+ this._send = snedProc;
300
311
  this._data.headers ??= {};
301
312
  this._data.headers['Content-Type'] = 'application/x-www-form-urlencoded';
302
313
  return this;
303
314
  }
304
- /**发送文件
305
- * 请求参数为 (filepath:string, filename?: string)
306
- */
315
+ /**发送文件 */
307
316
  sendFile() {
308
- const proc = {
309
- proc: (opt, filepath, filename) => {
310
- const formData = new form_data_1.default();
311
- filename = filename ?? pathe_1.default.basename(filepath);
312
- formData.append(filename, fs_1.default.createReadStream(filepath));
313
- opt.headers = formData.getHeaders();
314
- const procReq = (req) => {
317
+ const proc = (opt, arg) => {
318
+ let { filepath, filename } = arg;
319
+ const formData = new form_data_1.default();
320
+ filename = filename ?? pathe_1.default.basename(filepath);
321
+ formData.append(filename, fs_1.default.createReadStream(filepath));
322
+ opt.headers = formData.getHeaders();
323
+ return {
324
+ proc: (req) => {
315
325
  formData.pipe(req);
316
- };
317
- return procReq;
318
- },
326
+ }
327
+ };
319
328
  };
320
329
  this._send = proc;
321
330
  this._data.headers ??= {};
@@ -335,11 +344,11 @@ class UtilHttp {
335
344
  /**发送请求
336
345
  * @param datas - 数据对象
337
346
  */
338
- async once(...datas) {
339
- const fullopt = this._data;
340
- const proc = await this._send.proc(fullopt, ...datas);
341
- const { reduce, init, parse } = this._accept;
342
- const res = await UtilHttp.request(fullopt, proc, reduce, init);
347
+ async once(arg) {
348
+ const fullopt = { ...this._data, ...arg.option ?? {} };
349
+ const sendProc = await this._send(fullopt, arg);
350
+ const { parse, ...acceptProc } = await this._accept(arg);
351
+ const res = await UtilHttp.request(fullopt, sendProc, acceptProc);
343
352
  return parse(res);
344
353
  }
345
354
  /**重复发送网络请求
@@ -347,52 +356,76 @@ class UtilHttp {
347
356
  * @param retries - 重试选项 默认 延迟:1000ms 间隔:180_000ms 重试:3次
348
357
  * @param datas - 数据对象
349
358
  */
350
- async retry(opt, ...datas) {
351
- let { retries, verify } = opt;
359
+ async retry(arg) {
360
+ let { retries, verify } = arg;
352
361
  retries ??= {};
353
362
  retries.tryDelay = retries.tryDelay ?? 1000;
354
- const procFn = async () => this.once(...datas);
363
+ const procFn = async () => this.once(arg);
355
364
  return UtilFunctions_1.UtilFunc.retryPromise(procFn, verify, retries);
356
365
  }
357
366
  /**发送网络请求
358
- * @param option - 网络请求选项
359
- * @param proc - 请求处理函数 需调用req.end()
360
- * @param reduce - 数据处理函数
361
- * @param init - 初始数据
367
+ * @param option - 网络请求选项
368
+ * @param reqProc - 请求处理函数 需调用req.end()
369
+ * @param acceptProc - 响应处理数据
362
370
  */
363
- static async request(option, proc, reduce, init) {
371
+ static async request(option, sendProc, acceptProc) {
372
+ const { reduce: reqReduce, init: reqInit } = acceptProc;
373
+ const { proc: reqProc } = sendProc;
364
374
  const { protocol, timeout, ...baseReqOpt } = option;
375
+ const plusTimeout = (timeout ?? 0) + 1000;
365
376
  const hasTimeLimit = (timeout ? timeout >= 10_000 : false);
366
377
  const flagName = `UtilCom.request ${protocol}${baseReqOpt.method} ${UtilFunctions_1.UtilFunc.genUUID()}`;
367
378
  const reduceQueue = new js_utils_1.PromiseQueue();
368
379
  let dataPromise = null;
369
380
  return new Promise(async (resolve, rejecte) => {
370
- const resFunc = (res) => {
381
+ const finallyTimeout = hasTimeLimit
382
+ ? setTimeout(() => {
383
+ UtilLogger_1.SLogger.warn(`${flagName} finallyTimeout 超时 ${timeout} ms, 终止请求`);
384
+ req.destroy();
385
+ resolve(undefined);
386
+ }, plusTimeout)
387
+ : undefined;
388
+ const finallyResolve = (t) => {
389
+ clearTimeout(finallyTimeout);
390
+ resolve(t);
391
+ };
392
+ const resFunc = async (res) => {
371
393
  try {
372
394
  //请求超时
373
395
  if (hasTimeLimit) {
374
396
  res.setTimeout(timeout, () => {
375
- UtilLogger_1.SLogger.warn(`${flagName} 接收反馈超时: ${timeout} ms`);
376
- res.destroy();
397
+ UtilLogger_1.SLogger.warn(`${flagName} http.response 触发 ${timeout} ms 超时, 继续挂起等待`);
377
398
  });
378
399
  }
379
- let mergedata = init;
400
+ let mergedata;
401
+ try {
402
+ mergedata = await reqInit(res);
403
+ }
404
+ catch (err) {
405
+ UtilLogger_1.SLogger.error(`${flagName} init函数错误:`, err);
406
+ finallyResolve(undefined);
407
+ return;
408
+ }
380
409
  res.setEncoding(option.responseEncode ?? 'utf8');
381
410
  res.on('data', chunk => {
382
411
  dataPromise = reduceQueue
383
- .enqueue(async () => mergedata = await reduce(mergedata, chunk))
384
- .catch(err => {
385
- UtilLogger_1.SLogger.error(`${flagName} reduce函数错误:`, err, `chunk:${chunk}\nmergedata:`, mergedata);
386
- resolve(undefined);
412
+ .enqueue(async () => {
413
+ try {
414
+ mergedata = await reqReduce(mergedata, chunk);
415
+ }
416
+ catch (err) {
417
+ UtilLogger_1.SLogger.error(`${flagName} reduce函数错误:`, err, `chunk:${chunk}\nmergedata:`, mergedata);
418
+ finallyResolve(undefined);
419
+ }
387
420
  });
388
421
  });
389
422
  res.on('error', err => {
390
423
  UtilLogger_1.SLogger.warn(`${flagName} 接收反馈错误:`, err);
391
- resolve(undefined);
424
+ finallyResolve(undefined);
392
425
  });
393
426
  res.on('end', async () => {
394
427
  await dataPromise;
395
- resolve({
428
+ finallyResolve({
396
429
  headers: res.headers,
397
430
  statusCode: res.statusCode,
398
431
  data: mergedata,
@@ -401,7 +434,7 @@ class UtilHttp {
401
434
  }
402
435
  catch (err) {
403
436
  UtilLogger_1.SLogger.warn(`${flagName} 未知错误:`, err);
404
- resolve(undefined);
437
+ finallyResolve(undefined);
405
438
  return;
406
439
  }
407
440
  };
@@ -412,20 +445,19 @@ class UtilHttp {
412
445
  //请求超时
413
446
  if (hasTimeLimit) {
414
447
  req.setTimeout(timeout, () => {
415
- UtilLogger_1.SLogger.warn(`${flagName} 发送请求超时: ${timeout} ms`);
416
- req.destroy();
448
+ UtilLogger_1.SLogger.warn(`${flagName} http.request 触发 ${timeout} ms 超时, 继续挂起等待`);
417
449
  });
418
450
  }
419
451
  req.on('error', err => {
420
452
  UtilLogger_1.SLogger.warn(`${flagName} 发送请求错误:`, err);
421
- resolve(undefined);
453
+ finallyResolve(undefined);
422
454
  });
423
455
  try {
424
- await proc(req);
456
+ await reqProc(req);
425
457
  }
426
458
  catch (err) {
427
459
  UtilLogger_1.SLogger.error(`${flagName} proc函数错误:`, err);
428
- resolve(undefined);
460
+ finallyResolve(undefined);
429
461
  }
430
462
  });
431
463
  }
@@ -446,24 +478,30 @@ if (false)
446
478
  const tool = UtilHttp
447
479
  .url('https://httpbin.org/post')
448
480
  .post()
449
- .finalize({ timeout: 10000 });
481
+ .option({ timeout: 20000 });
450
482
  //json
451
483
  const sj = await tool.clone()
452
484
  .sendJson()
453
485
  .acceptJson()
454
- .once({ test: 1 });
486
+ .once({
487
+ json: { test: 1 },
488
+ });
455
489
  console.log(sj);
456
490
  //form
457
491
  const sf = await tool.clone()
458
492
  .sendForm()
459
493
  .acceptJson()
460
- .once({ test: 1 });
494
+ .once({
495
+ form: { test: 1 }
496
+ });
461
497
  console.log(sf);
462
498
  //query
463
499
  const sq = await tool.clone()
464
500
  .sendQuery()
465
501
  .acceptJson()
466
- .once({ test: 1 });
502
+ .once({
503
+ query: { test: 1 }
504
+ });
467
505
  console.log(sq);
468
506
  const filepath = pathe_1.default.join(__dirname, '..', 'input.wav');
469
507
  //formData
@@ -477,6 +515,8 @@ if (false)
477
515
  const sfile = await tool.clone()
478
516
  .sendFile()
479
517
  .acceptJson()
480
- .once(filepath);
518
+ .once({
519
+ filepath: filepath
520
+ });
481
521
  console.log(sfile);
482
522
  })());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zwa73/utils",
3
- "version": "1.0.231",
3
+ "version": "1.0.233",
4
4
  "description": "my utils",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {