@base-web-kits/base-tools-web 1.3.18 → 1.4.0

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.
@@ -10,6 +10,15 @@ export type RequestData = string | ArrayBuffer | ArrayBufferView | Blob | FormDa
10
10
  * 响应数据类型
11
11
  */
12
12
  export type ResponseData = string | ArrayBuffer | Blob | Record<string, unknown> | unknown[] | null;
13
+ /** 请求前转换上下文 */
14
+ export type TransformRequestContext<D extends RequestData = RequestData> = {
15
+ url: string;
16
+ method: RequestMethod;
17
+ header: Record<string, string>;
18
+ data?: D;
19
+ };
20
+ /** 请求前转换结果 */
21
+ export type TransformRequestResult<D extends RequestData = RequestData> = Partial<Pick<TransformRequestContext<D>, 'url' | 'header' | 'data'>>;
13
22
  /**
14
23
  * 发起请求的配置 (对外,参数可选)
15
24
  */
@@ -54,8 +63,10 @@ export type RequestConfigBase<D extends RequestData = RequestData> = {
54
63
  showLog?: boolean;
55
64
  /** 成功和失败时,额外输出的日志数据 (可覆盖内部log参数,如'name') */
56
65
  logExtra?: Record<string, unknown>;
66
+ /** 请求前的数据转换, 可用于加密 header、data 或重写 url */
67
+ transformRequest?: (ctx: TransformRequestContext<D>) => TransformRequestResult<D> | Promise<TransformRequestResult<D>>;
57
68
  /** 响应数据的转换 */
58
- resMap?: (data: ResponseData) => ResponseData;
69
+ transformResponse?: (data: ResponseData) => ResponseData;
59
70
  /** 获取请求对象, 用于取消请求 */
60
71
  onTaskReady?: (task: RequestTask) => void;
61
72
  /**
@@ -101,7 +112,8 @@ export type RequestTask = {
101
112
  * export function requestApi<T>(config: RequestConfig) {
102
113
  * return request<T>({
103
114
  * header: { token: 'xx', version: 'xx', tid: 'xx' }, // 会自动过滤空值
104
- * // resMap: (res) => res, // 响应数据的转换, 如解密操作 (可选)
115
+ * // transformRequest: ({ header, data }) => ({ header, data }), // 请求前转换, 如加密请求头和请求参数 (可选)
116
+ * // transformResponse: (res) => res, // 响应数据的转换, 如解密操作 (可选)
105
117
  * resKey: 'data',
106
118
  * msgKey: 'message',
107
119
  * codeKey: 'status',
@@ -1 +1 @@
1
- {"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../src/web/network/request.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../src/web/network/request.ts"],"names":[],"mappings":"AAKA,OAAO,EAAa,KAAK,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAG5E,aAAa;AACb,MAAM,MAAM,aAAa,GACrB,KAAK,GACL,MAAM,GACN,KAAK,GACL,QAAQ,GACR,SAAS,GACT,MAAM,GACN,SAAS,GACT,OAAO,GACP,OAAO,CAAC;AAEZ;;;GAGG;AACH,MAAM,MAAM,WAAW,GACnB,MAAM,GACN,WAAW,GACX,eAAe,GACf,IAAI,GACJ,QAAQ,GACR,eAAe,GACf,cAAc,CAAC,UAAU,CAAC,GAC1B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACvB,OAAO,EAAE,GACT,IAAI,CAAC;AAET;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,WAAW,GAAG,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,EAAE,GAAG,IAAI,CAAC;AAEpG,eAAe;AACf,MAAM,MAAM,uBAAuB,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,IAAI;IACzE,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,aAAa,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,IAAI,CAAC,EAAE,CAAC,CAAC;CACV,CAAC;AAEF,cAAc;AACd,MAAM,MAAM,sBAAsB,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,IAAI,OAAO,CAC/E,IAAI,CAAC,uBAAuB,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC,CAC5D,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC;AAE/F;;GAEG;AACH,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,IAAI;IACnE,WAAW;IACX,GAAG,EAAE,MAAM,CAAC;IAEZ,WAAW;IACX,MAAM,CAAC,EAAE,aAAa,CAAC;IAEvB,gEAAgE;IAChE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IAEtE,WAAW;IACX,IAAI,CAAC,EAAE,CAAC,CAAC;IAET,0BAA0B;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,uDAAuD;IACvD,MAAM,EAAE,MAAM,GAAG,KAAK,CAAC;IAEvB,mCAAmC;IACnC,MAAM,EAAE,MAAM,CAAC;IAEf,oCAAoC;IACpC,OAAO,EAAE,MAAM,CAAC;IAEhB,kDAAkD;IAClD,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,YAAY;IACZ,WAAW,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IAEjC,cAAc;IACd,WAAW,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IAEjC,uBAAuB;IACvB,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB,4CAA4C;IAC5C,YAAY,CAAC,EAAE,MAAM,GAAG,aAAa,GAAG,MAAM,CAAC;IAE/C,2DAA2D;IAC3D,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,wBAAwB;IACxB,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB,oCAAoC;IACpC,WAAW,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAE/B,sBAAsB;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAEnC,0CAA0C;IAC1C,gBAAgB,CAAC,EAAE,CACjB,GAAG,EAAE,uBAAuB,CAAC,CAAC,CAAC,KAC5B,sBAAsB,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC;IAEpE,cAAc;IACd,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,YAAY,CAAC;IAEzD,qBAAqB;IACrB,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,IAAI,CAAC;IAE1C;;;;;;;;;OASG;IACH,SAAS,CAAC,EAAE,eAAe,CAAC;CAC7B,CAAC;AAEF,sBAAsB;AACtB,MAAM,MAAM,WAAW,GAAG;IACxB,WAAW;IACX,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,CAAC;AAuBF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmFG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,CAAC,SAAS,WAAW,GAAG,WAAW,EAAE,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAAC,cAsP3F;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,uBAM1D;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,iBAAiB,CAAC,QAAQ,CAAC,0BAQtE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@base-web-kits/base-tools-web",
3
- "version": "1.3.18",
3
+ "version": "1.4.0",
4
4
  "sideEffects": false,
5
5
  "description": "Independent Web utilities package built from src/web.",
6
6
  "keywords": [
@@ -23,8 +23,8 @@ export type WebApiConfig<Res = any, Err = any> = {
23
23
  /** 是否显示日志, 默认 true */
24
24
  showLog?: boolean;
25
25
 
26
- /** 响应数据的转换, 如解密操作 (返回值在成功日志中输出'resMap'字段) */
27
- resMap?: (res: any) => Res;
26
+ /** 响应数据的转换, 如解密操作 (返回值在成功日志中输出'transformResponse'字段) */
27
+ transformResponse?: (res: any) => Res;
28
28
 
29
29
  /** 成功和失败时,额外输出的日志数据 (可覆盖内部log参数,如'name') */
30
30
  logExtra?: Record<string, unknown>;
@@ -50,7 +50,7 @@ export function enhanceWebApi<Option = any, Res = any, Err = any, Config = any>(
50
50
  toastSuccess = false,
51
51
  toastError = true,
52
52
  showLog = true,
53
- resMap,
53
+ transformResponse,
54
54
  logExtra,
55
55
  } = finalConfig;
56
56
 
@@ -72,14 +72,14 @@ export function enhanceWebApi<Option = any, Res = any, Err = any, Config = any>(
72
72
  .then((res) => {
73
73
  if (showLoading) hideLoadingFn?.();
74
74
 
75
- const finalRes = resMap ? resMap(res) : res;
75
+ const finalRes = transformResponse ? transformResponse(res) : res;
76
76
 
77
77
  if (showLog) {
78
78
  const logData: AppLogInfo = { name: fname, status: 'success', option, ...logExtra };
79
79
 
80
- if (resMap) {
80
+ if (transformResponse) {
81
81
  logData.res = res; // 输出原始数据
82
- logData.resMap = cloneDeep(finalRes); // 深拷贝处理后数据,避免外部修改对象,造成输出不一致
82
+ logData.transformResponse = cloneDeep(finalRes); // 深拷贝处理后数据,避免外部修改对象,造成输出不一致
83
83
  } else {
84
84
  logData.res = cloneDeep(res); // 深拷贝原始数据,避免外部修改对象,造成输出不一致
85
85
  }
@@ -39,6 +39,19 @@ export type RequestData =
39
39
  */
40
40
  export type ResponseData = string | ArrayBuffer | Blob | Record<string, unknown> | unknown[] | null;
41
41
 
42
+ /** 请求前转换上下文 */
43
+ export type TransformRequestContext<D extends RequestData = RequestData> = {
44
+ url: string;
45
+ method: RequestMethod;
46
+ header: Record<string, string>;
47
+ data?: D;
48
+ };
49
+
50
+ /** 请求前转换结果 */
51
+ export type TransformRequestResult<D extends RequestData = RequestData> = Partial<
52
+ Pick<TransformRequestContext<D>, 'url' | 'header' | 'data'>
53
+ >;
54
+
42
55
  /**
43
56
  * 发起请求的配置 (对外,参数可选)
44
57
  */
@@ -102,8 +115,13 @@ export type RequestConfigBase<D extends RequestData = RequestData> = {
102
115
  /** 成功和失败时,额外输出的日志数据 (可覆盖内部log参数,如'name') */
103
116
  logExtra?: Record<string, unknown>;
104
117
 
118
+ /** 请求前的数据转换, 可用于加密 header、data 或重写 url */
119
+ transformRequest?: (
120
+ ctx: TransformRequestContext<D>,
121
+ ) => TransformRequestResult<D> | Promise<TransformRequestResult<D>>;
122
+
105
123
  /** 响应数据的转换 */
106
- resMap?: (data: ResponseData) => ResponseData;
124
+ transformResponse?: (data: ResponseData) => ResponseData;
107
125
 
108
126
  /** 获取请求对象, 用于取消请求 */
109
127
  onTaskReady?: (task: RequestTask) => void;
@@ -134,6 +152,17 @@ export type RequestTask = {
134
152
  */
135
153
  type SseTask = { parser: SSEParser | undefined | null };
136
154
 
155
+ /** 日志请求 */
156
+ type RequestLogConfig = {
157
+ url?: string;
158
+ data?: unknown;
159
+ header?: unknown;
160
+ method?: RequestMethod;
161
+ logExtra?: Record<string, unknown>;
162
+ showLog?: boolean;
163
+ resKey?: RequestConfigBase['resKey'];
164
+ };
165
+
137
166
  /** 请求缓存 */
138
167
  const requestCache = new Map<string, { res: unknown; expire: number }>();
139
168
 
@@ -163,7 +192,8 @@ const requestCache = new Map<string, { res: unknown; expire: number }>();
163
192
  * export function requestApi<T>(config: RequestConfig) {
164
193
  * return request<T>({
165
194
  * header: { token: 'xx', version: 'xx', tid: 'xx' }, // 会自动过滤空值
166
- * // resMap: (res) => res, // 响应数据的转换, 如解密操作 (可选)
195
+ * // transformRequest: ({ header, data }) => ({ header, data }), // 请求前转换, 如加密请求头和请求参数 (可选)
196
+ * // transformResponse: (res) => res, // 响应数据的转换, 如解密操作 (可选)
167
197
  * resKey: 'data',
168
198
  * msgKey: 'message',
169
199
  * codeKey: 'status',
@@ -236,7 +266,8 @@ export function request<T, D extends RequestData = RequestData>(config: RequestC
236
266
  toastError = true,
237
267
  enableChunked = false,
238
268
  cacheTime,
239
- resMap,
269
+ transformRequest,
270
+ transformResponse,
240
271
  responseType = 'json',
241
272
  timeout = 60000,
242
273
  onTaskReady,
@@ -265,29 +296,53 @@ export function request<T, D extends RequestData = RequestData>(config: RequestC
265
296
  return new Promise<T>((resolve, reject) => {
266
297
  const execute = async () => {
267
298
  const isGet = method === 'GET';
268
- const isObjectData = isPlainObject(data);
269
- const isArrayData = !isObjectData && Array.isArray(data);
270
299
 
271
300
  // 2.1 参数处理
272
301
  // 参数过滤 undefined
273
- const fillData = isObjectData ? filterRequestData(data) : data;
302
+ let fillData = isPlainObject(data) ? filterRequestData(data) : data;
274
303
 
275
304
  // 请求头过滤空值 (undefined, null, "")
276
- const fillHeader = filterRequestHeader(header);
305
+ let fillHeader = filterRequestHeader(header);
306
+
307
+ // 请求前转换
308
+ let fillUrl = url;
309
+ const requestTransformer = transformRequest;
310
+ if (requestTransformer) {
311
+ const transformed =
312
+ (await requestTransformer({
313
+ url: fillUrl,
314
+ method,
315
+ header: { ...fillHeader },
316
+ data: fillData as D,
317
+ })) || {};
318
+
319
+ if (transformed.url !== undefined) fillUrl = transformed.url;
320
+ if (transformed.header !== undefined) fillHeader = filterRequestHeader(transformed.header);
321
+ if (transformed.data !== undefined) {
322
+ const transformedData = transformed.data;
323
+ fillData = isPlainObject(transformedData)
324
+ ? filterRequestData(transformedData as Record<string, any>)
325
+ : transformedData;
326
+ }
327
+ }
277
328
 
278
329
  // 获取 Content-Type (忽略大小写)
279
330
  const contentTypeKey = Object.keys(fillHeader).find(
280
331
  (k) => k.toLowerCase() === 'content-type',
281
332
  );
282
333
  const contentType = contentTypeKey ? String(fillHeader[contentTypeKey]).toLowerCase() : '';
334
+ const isObjectData = isPlainObject(fillData);
335
+ const isArrayData = !isObjectData && Array.isArray(fillData);
283
336
 
284
337
  if (!isGet && fillData && (isObjectData || isArrayData) && !contentType) {
285
338
  fillHeader['Content-Type'] = 'application/json';
286
339
  }
287
340
 
288
341
  // 2.2 处理 URL 和 Body
289
- const fillUrl =
290
- isGet && isObjectData ? appendUrlParam(url, fillData as Record<string, unknown>) : url;
342
+ fillUrl =
343
+ isGet && isPlainObject(fillData)
344
+ ? appendUrlParam(fillUrl, fillData as Record<string, unknown>)
345
+ : fillUrl;
291
346
 
292
347
  let fillBody: BodyInit | null | undefined;
293
348
 
@@ -390,8 +445,8 @@ export function request<T, D extends RequestData = RequestData>(config: RequestC
390
445
  // 隐藏 Loading
391
446
  if (showLoading) appConfig.hideLoading?.();
392
447
 
393
- // 响应拦截
394
- const res = resMap ? resMap(resData) : resData;
448
+ // 响应数据转换
449
+ const res = transformResponse ? transformResponse(resData) : resData;
395
450
 
396
451
  // 2.10 业务状态码解析
397
452
  const code = getObjectValue(res, codeKey);
@@ -431,7 +486,7 @@ export function request<T, D extends RequestData = RequestData>(config: RequestC
431
486
  }
432
487
 
433
488
  if (!isAbortError && toastError)
434
- appConfig.toast?.({ status, msg: `请求失败,${String(e)}` });
489
+ appConfig.toast?.({ status, msg: `请求失败,${JSON.stringify(e)}` });
435
490
  logRequestInfo({ status, config: logConfig, startTime, e });
436
491
  reject(e);
437
492
  } finally {
@@ -471,7 +526,7 @@ export function filterRequestHeader(header: RequestConfigBase['header']) {
471
526
  * 日志输出
472
527
  */
473
528
  function logRequestInfo(options: {
474
- config: RequestConfigBase<RequestData> & { url?: string };
529
+ config: RequestLogConfig;
475
530
  fromCache?: boolean;
476
531
  startTime: number;
477
532
  status: 'success' | 'fail';
@@ -506,7 +561,7 @@ function logRequestInfo(options: {
506
561
  info.res = cloneDeep(res); // 深拷贝,避免外部修改对象,造成输出不一致
507
562
  log('info', info);
508
563
  } else {
509
- info.e = e instanceof Error ? { name: e.name, message: e.message, stack: e.stack } : String(e); // Error需转为普通对象,否则发送网络日志会序列化成空对象
564
+ info.e = e instanceof Error ? { name: e.name, message: e.message, stack: e.stack } : e; // Error需转为普通对象,否则发送网络日志会序列化成空对象
510
565
  log('error', info);
511
566
  }
512
567
  }