uniapp-request-sdk 1.5.1 → 1.6.1

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/README.md CHANGED
@@ -5,6 +5,49 @@
5
5
  [![npm version](https://img.shields.io/npm/v/uniapp-request-sdk.svg)](https://www.npmjs.com/package/uniapp-request-sdk)
6
6
  [![license](https://img.shields.io/npm/l/uniapp-request-sdk.svg)](https://github.com/yourusername/uniapp-request-sdk)
7
7
 
8
+ ## 目录
9
+
10
+ - [适用场景](#适用场景)
11
+ - [核心能力](#核心能力)
12
+ - [安装](#安装)
13
+ - [5 分钟接入](#5-分钟接入)
14
+ - [快速开始](#快速开始)
15
+ - [工程接入建议](#工程接入建议)
16
+ - [详细配置](#详细配置)
17
+ - [API 文档](#api-文档)
18
+ - [文件上传](#文件上传)
19
+ - [使用示例](#使用示例)
20
+ - [响应格式](#响应格式)
21
+ - [错误处理](#错误处理)
22
+ - [平台差异处理](#平台差异处理)
23
+ - [配置参数详解](#配置参数详解)
24
+ - [请求头预处理器(新增功能)](#请求头预处理器新增功能)
25
+ - [最佳实践](#最佳实践)
26
+ - [企业级实战案例](#企业级实战案例)
27
+ - [常见问题](#常见问题)
28
+ - [版本历史](#版本历史)
29
+
30
+ ## 适用场景
31
+
32
+ 这个 SDK 适合以下场景:
33
+
34
+ - uni-app 项目中统一封装 `GET`、`POST`、`PUT`、`DELETE`、`uploadFile`
35
+ - 需要自动处理 `403` 后重新获取 token 再重试的业务场景
36
+ - 需要为所有请求统一追加公共请求头、日志字段、签名字段
37
+ - 需要在 App、小程序、H5 等多端尽量复用一套网络层逻辑
38
+ - 需要在上传文件时监听进度并驱动页面上的进度条展示
39
+
40
+ 如果你的服务端返回结构不是本文档中的默认格式,也可以基于当前 SDK 继续二次封装。
41
+
42
+ ## 核心能力
43
+
44
+ - 统一的请求实例管理,支持运行时动态更新参数
45
+ - 支持全局公共请求头与单次请求头合并
46
+ - 支持同步或异步的请求头预处理器 `headerProcessor`
47
+ - 支持 `401`、`403`、网络异常、超时等通用场景处理
48
+ - 支持文件上传、上传超时控制和上传进度监听
49
+ - 默认兼容相对路径与完整 URL 两种调用方式
50
+
8
51
  ## 特性
9
52
 
10
53
  - ✅ **自动重试机制** - 请求失败自动重试,可配置重试次数和延迟
@@ -30,6 +73,57 @@ npm install uniapp-request-sdk
30
73
  yarn add uniapp-request-sdk
31
74
  ```
32
75
 
76
+ ## 5 分钟接入
77
+
78
+ ```typescript
79
+ import UniRequest from 'uniapp-request-sdk';
80
+
81
+ const request = new UniRequest({
82
+ baseUrl: 'https://api.example.com',
83
+ timeout: 10000,
84
+ uploadTimeout: 30000,
85
+ tokenHeader: 'Authorization',
86
+ tokenPrefix: 'Bearer ',
87
+ onErrorHandler: (error) => {
88
+ console.error('请求失败:', error);
89
+ },
90
+ });
91
+
92
+ export default request;
93
+ ```
94
+
95
+ ```typescript
96
+ import request from '@/utils/request';
97
+
98
+ export function getUserProfile() {
99
+ return request.get('/user/profile');
100
+ }
101
+
102
+ export function updateUserProfile(data: Record<string, any>) {
103
+ return request.post('/user/profile/update', data);
104
+ }
105
+
106
+ export function uploadAvatar(filePath: string) {
107
+ return request.uploadFile(
108
+ '/user/avatar/upload',
109
+ filePath,
110
+ undefined,
111
+ 'file',
112
+ undefined,
113
+ (progress) => {
114
+ console.log('上传进度:', progress.progress);
115
+ },
116
+ );
117
+ }
118
+ ```
119
+
120
+ 完成以上两步后,你的工程已经具备:
121
+
122
+ - 统一请求入口
123
+ - 统一错误处理能力
124
+ - 文件上传能力
125
+ - 上传进度监听能力
126
+
33
127
  ## 快速开始
34
128
 
35
129
  ### 基础使用
@@ -58,10 +152,43 @@ await request.put('/users/1', { name: 'Jane' });
58
152
  // 6. 上传文件
59
153
  const uploadResult = await request.uploadFile(
60
154
  '/upload',
61
- '/path/to/file.jpg'
155
+ '/path/to/file.jpg',
156
+ undefined,
157
+ 'file',
158
+ undefined,
159
+ (progress) => {
160
+ console.log('当前上传进度:', progress.progress);
161
+ },
62
162
  );
63
163
  ```
64
164
 
165
+ ## 工程接入建议
166
+
167
+ 推荐在业务工程中按下面的方式组织网络层:
168
+
169
+ ```text
170
+ src/
171
+ ├── api/ # 按业务域拆分接口
172
+ │ ├── user.ts
173
+ │ ├── auth.ts
174
+ │ └── workflow.ts
175
+ ├── utils/
176
+ │ └── request.ts # SDK 实例初始化
177
+ └── pages/ # 页面中只调用 api 层
178
+ ```
179
+
180
+ 推荐职责划分如下:
181
+
182
+ - `utils/request.ts`:只负责创建 `UniRequest` 实例和放置全局配置
183
+ - `api/*.ts`:只负责定义接口函数,不写 UI 逻辑
184
+ - `pages/*` 或 `components/*`:只消费 `api` 层返回的数据
185
+
186
+ 推荐这样做的原因:
187
+
188
+ - 请求配置只有一份,便于统一维护
189
+ - token、签名、超时、日志字段不会散落在页面中
190
+ - 后续替换域名、调整 header、增加埋点时改动范围最小
191
+
65
192
  ## 详细配置
66
193
 
67
194
  ### 初始化配置
@@ -214,8 +341,70 @@ const result = await request.uploadFile<ResponseType>(
214
341
  'X-Upload-Token': 'upload-token',
215
342
  }
216
343
  );
344
+
345
+ // 监听上传进度
346
+ const result = await request.uploadFile<ResponseType>(
347
+ '/upload',
348
+ '/path/to/file.jpg',
349
+ { description: 'My upload' },
350
+ 'file',
351
+ undefined,
352
+ (progress) => {
353
+ console.log('上传进度百分比:', progress.progress);
354
+ console.log('已上传字节数:', progress.totalBytesSent);
355
+ console.log('总字节数:', progress.totalBytesExpectedToSend);
356
+ }
357
+ );
358
+ ```
359
+
360
+ ## 文件上传
361
+
362
+ ### 方法签名
363
+
364
+ ```typescript
365
+ uploadFile<T>(
366
+ url: string,
367
+ filePath: string,
368
+ formData?: Record<string, any>,
369
+ name = 'file',
370
+ header?: Record<string, string>,
371
+ onProgressUpdateCallback?: (result: OnProgressUpdateResult) => void,
372
+ ): Promise<T>
217
373
  ```
218
374
 
375
+ ### 参数说明
376
+
377
+ | 参数 | 类型 | 是否必填 | 说明 |
378
+ |------|------|----------|------|
379
+ | `url` | `string` | 是 | 上传接口地址,支持相对路径和完整 URL |
380
+ | `filePath` | `string` | 是 | 待上传文件的本地临时路径 |
381
+ | `formData` | `Record<string, any>` | 否 | 附加的表单字段 |
382
+ | `name` | `string` | 否 | 文件字段名,默认是 `file` |
383
+ | `header` | `Record<string, string>` | 否 | 当前上传请求的自定义请求头 |
384
+ | `onProgressUpdateCallback` | `(result) => void` | 否 | 上传进度回调 |
385
+
386
+ ### 上传进度回调说明
387
+
388
+ 当传入 `onProgressUpdateCallback` 后,SDK 会在内部调用 `uni.uploadFile()` 返回的 `UploadTask.onProgressUpdate()` 进行绑定。
389
+
390
+ 回调参数结构如下:
391
+
392
+ ```typescript
393
+ type OnProgressUpdateResult = {
394
+ progress?: number;
395
+ totalBytesSent?: number;
396
+ totalBytesExpectedToSend?: number;
397
+ };
398
+ ```
399
+
400
+ ### 使用注意事项
401
+
402
+ - `onProgressUpdateCallback` 是可选参数,不传时上传行为与旧版本保持一致
403
+ - 如果只想传进度回调、不需要自定义 `header`,第 5 个参数需要显式传 `undefined`
404
+ - 上传接口底层仍然返回 Promise,适合继续用 `await` 或 `.then()`
405
+ - 如果上传过程中发生失败并触发重试,进度回调会按“当前这次上传尝试”的进度继续上报
406
+ - 如果服务端返回的是字符串 JSON,SDK 会自动尝试解析后再取其中的 `data`
407
+
219
408
  ## 使用示例
220
409
 
221
410
  ### 示例 1:基础请求
@@ -327,6 +516,47 @@ async function selectAndUploadFile() {
327
516
  }
328
517
  ```
329
518
 
519
+ ### 示例 4-1:带上传进度的文件上传
520
+
521
+ ```typescript
522
+ import UniRequest from 'uniapp-request-sdk';
523
+
524
+ const request = new UniRequest({
525
+ baseUrl: 'https://api.example.com',
526
+ uploadTimeout: 30000,
527
+ });
528
+
529
+ async function selectAndUploadFile() {
530
+ uni.chooseImage({
531
+ count: 1,
532
+ success: async (res) => {
533
+ const filePath = res.tempFilePaths[0];
534
+ let currentProgress = 0;
535
+
536
+ try {
537
+ const result = await request.uploadFile(
538
+ '/upload',
539
+ filePath,
540
+ {
541
+ category: 'avatar',
542
+ },
543
+ 'file',
544
+ undefined,
545
+ (progress) => {
546
+ currentProgress = progress.progress || 0;
547
+ console.log('上传中:', currentProgress);
548
+ },
549
+ );
550
+
551
+ console.log('上传完成:', result);
552
+ } catch (error) {
553
+ console.error('上传失败:', error, currentProgress);
554
+ }
555
+ },
556
+ });
557
+ }
558
+ ```
559
+
330
560
  ### 示例 5:实时生成签名
331
561
 
332
562
  ```typescript
@@ -973,6 +1203,8 @@ export default {
973
1203
 
974
1204
 
975
1205
 
1206
+ ## 常见问题
1207
+
976
1208
  ### Q: 如何处理跨域问题?
977
1209
 
978
1210
  A: 在 `baseUrl` 中包含代理路径,让后端或开发服务器代理请求。
package/dist/index.d.ts CHANGED
@@ -30,6 +30,9 @@ interface IParams {
30
30
  /** 用户名,用于日志排查使用 */
31
31
  username?: string;
32
32
  }
33
+ type UploadFileWithProgressOption = UploadFileOption & {
34
+ onProgressUpdateCallback?: (result: OnProgressUpdateResult) => void;
35
+ };
33
36
  declare function requestPromise(options?: RequestOptions & {
34
37
  timeout: number;
35
38
  }): Promise<RequestSuccessCallbackResult>;
@@ -68,7 +71,7 @@ declare class UniRequest {
68
71
  header?: RequestOptions['header'];
69
72
  /** 超时时间 */
70
73
  timeout?: number;
71
- } & RequestOptions & UploadFileOption, callbackPromise?: typeof requestPromise): Promise<T>;
74
+ } & RequestOptions & UploadFileWithProgressOption, callbackPromise?: typeof requestPromise): Promise<T>;
72
75
  /**
73
76
  * post请求
74
77
  * @param url
@@ -82,14 +85,15 @@ declare class UniRequest {
82
85
  put<T>(url: string, data?: {}, header?: Record<string, string>): Promise<T>;
83
86
  /**
84
87
  * 文件上传
85
- * @param url 上传的url
86
- * @param filePath 文件路径
87
- * @param formData HTTP 请求中其他额外的 form data
88
- * @param name 文件对应的 key , 开发者在服务器端通过这个 key 可以获取到文件二进制内容,默认key为file
89
- * @param header
90
- * @returns
88
+ * @param url 上传接口地址;支持相对路径和完整的 http/https 地址
89
+ * @param filePath 待上传文件的本地临时路径
90
+ * @param formData 额外的表单字段,会与文件一起作为 multipart/form-data 提交
91
+ * @param name 文件字段名;服务端通过该字段读取文件内容,默认值为 file
92
+ * @param header 当前上传请求的自定义请求头;会与实例级公共请求头合并
93
+ * @param onProgressUpdateCallback 上传进度回调;传入后会绑定到 uni.uploadFile 返回的 UploadTask.onProgressUpdate
94
+ * @returns 返回一个 Promise;成功时解析服务端响应中的 data 字段,失败时抛出错误信息
91
95
  */
92
- uploadFile<T>(url: string, filePath: string, formData?: Record<string, any>, name?: string, header?: Record<string, string>): Promise<T>;
96
+ uploadFile<T>(url: string, filePath: string, formData?: Record<string, any>, name?: string, header?: Record<string, string>, onProgressUpdateCallback?: (result: OnProgressUpdateResult) => void): Promise<T>;
93
97
  }
94
98
 
95
99
  export { IParams, UniRequest as default };
package/dist/index.esm.js CHANGED
@@ -366,6 +366,33 @@ function _toPropertyKey(arg) {
366
366
  return typeof key === "symbol" ? key : String(key);
367
367
  }
368
368
 
369
+ /*! *****************************************************************************
370
+ Copyright (c) Microsoft Corporation.
371
+
372
+ Permission to use, copy, modify, and/or distribute this software for any
373
+ purpose with or without fee is hereby granted.
374
+
375
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
376
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
377
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
378
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
379
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
380
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
381
+ PERFORMANCE OF THIS SOFTWARE.
382
+ ***************************************************************************** */
383
+
384
+ function __rest(s, e) {
385
+ var t = {};
386
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
387
+ t[p] = s[p];
388
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
389
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
390
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
391
+ t[p[i]] = s[p[i]];
392
+ }
393
+ return t;
394
+ }
395
+
369
396
  /** 客户端交互内置事件名称 */
370
397
  var EVENT_NAME = {
371
398
  /** 通知APP退出到登录页面 */
@@ -381,10 +408,16 @@ function requestPromise(options) {
381
408
  }
382
409
  function uploadFilePromise(options) {
383
410
  return new Promise(function (res, rej) {
384
- uni.uploadFile(Object.assign(Object.assign({}, options), {
411
+ var _a = options || {},
412
+ onProgressUpdateCallback = _a.onProgressUpdateCallback,
413
+ uploadOptions = __rest(_a, ["onProgressUpdateCallback"]);
414
+ var uploadTask = uni.uploadFile(Object.assign(Object.assign({}, uploadOptions), {
385
415
  success: res,
386
416
  fail: rej
387
417
  }));
418
+ if (onProgressUpdateCallback) {
419
+ uploadTask.onProgressUpdate(onProgressUpdateCallback);
420
+ }
388
421
  });
389
422
  }
390
423
  /** 得到小程序的token */
@@ -642,18 +675,20 @@ var UniRequest = /*#__PURE__*/function () {
642
675
  }
643
676
  /**
644
677
  * 文件上传
645
- * @param url 上传的url
646
- * @param filePath 文件路径
647
- * @param formData HTTP 请求中其他额外的 form data
648
- * @param name 文件对应的 key , 开发者在服务器端通过这个 key 可以获取到文件二进制内容,默认key为file
649
- * @param header
650
- * @returns
678
+ * @param url 上传接口地址;支持相对路径和完整的 http/https 地址
679
+ * @param filePath 待上传文件的本地临时路径
680
+ * @param formData 额外的表单字段,会与文件一起作为 multipart/form-data 提交
681
+ * @param name 文件字段名;服务端通过该字段读取文件内容,默认值为 file
682
+ * @param header 当前上传请求的自定义请求头;会与实例级公共请求头合并
683
+ * @param onProgressUpdateCallback 上传进度回调;传入后会绑定到 uni.uploadFile 返回的 UploadTask.onProgressUpdate
684
+ * @returns 返回一个 Promise;成功时解析服务端响应中的 data 字段,失败时抛出错误信息
651
685
  */
652
686
  }, {
653
687
  key: "uploadFile",
654
688
  value: function uploadFile(url, filePath, formData) {
655
689
  var name = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'file';
656
690
  var header = arguments.length > 4 ? arguments[4] : undefined;
691
+ var onProgressUpdateCallback = arguments.length > 5 ? arguments[5] : undefined;
657
692
  return this.request({
658
693
  url: url,
659
694
  filePath: filePath,
@@ -661,7 +696,8 @@ var UniRequest = /*#__PURE__*/function () {
661
696
  name: name,
662
697
  header: header,
663
698
  timeout: this.uploadTimeout,
664
- method: 'POST'
699
+ method: 'POST',
700
+ onProgressUpdateCallback: onProgressUpdateCallback
665
701
  }, uploadFilePromise);
666
702
  }
667
703
  }]);
package/dist/index.umd.js CHANGED
@@ -372,6 +372,33 @@
372
372
  return typeof key === "symbol" ? key : String(key);
373
373
  }
374
374
 
375
+ /*! *****************************************************************************
376
+ Copyright (c) Microsoft Corporation.
377
+
378
+ Permission to use, copy, modify, and/or distribute this software for any
379
+ purpose with or without fee is hereby granted.
380
+
381
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
382
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
383
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
384
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
385
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
386
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
387
+ PERFORMANCE OF THIS SOFTWARE.
388
+ ***************************************************************************** */
389
+
390
+ function __rest(s, e) {
391
+ var t = {};
392
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
393
+ t[p] = s[p];
394
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
395
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
396
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
397
+ t[p[i]] = s[p[i]];
398
+ }
399
+ return t;
400
+ }
401
+
375
402
  /** 客户端交互内置事件名称 */
376
403
  var EVENT_NAME = {
377
404
  /** 通知APP退出到登录页面 */
@@ -387,10 +414,16 @@
387
414
  }
388
415
  function uploadFilePromise(options) {
389
416
  return new Promise(function (res, rej) {
390
- uni.uploadFile(Object.assign(Object.assign({}, options), {
417
+ var _a = options || {},
418
+ onProgressUpdateCallback = _a.onProgressUpdateCallback,
419
+ uploadOptions = __rest(_a, ["onProgressUpdateCallback"]);
420
+ var uploadTask = uni.uploadFile(Object.assign(Object.assign({}, uploadOptions), {
391
421
  success: res,
392
422
  fail: rej
393
423
  }));
424
+ if (onProgressUpdateCallback) {
425
+ uploadTask.onProgressUpdate(onProgressUpdateCallback);
426
+ }
394
427
  });
395
428
  }
396
429
  /** 得到小程序的token */
@@ -648,18 +681,20 @@
648
681
  }
649
682
  /**
650
683
  * 文件上传
651
- * @param url 上传的url
652
- * @param filePath 文件路径
653
- * @param formData HTTP 请求中其他额外的 form data
654
- * @param name 文件对应的 key , 开发者在服务器端通过这个 key 可以获取到文件二进制内容,默认key为file
655
- * @param header
656
- * @returns
684
+ * @param url 上传接口地址;支持相对路径和完整的 http/https 地址
685
+ * @param filePath 待上传文件的本地临时路径
686
+ * @param formData 额外的表单字段,会与文件一起作为 multipart/form-data 提交
687
+ * @param name 文件字段名;服务端通过该字段读取文件内容,默认值为 file
688
+ * @param header 当前上传请求的自定义请求头;会与实例级公共请求头合并
689
+ * @param onProgressUpdateCallback 上传进度回调;传入后会绑定到 uni.uploadFile 返回的 UploadTask.onProgressUpdate
690
+ * @returns 返回一个 Promise;成功时解析服务端响应中的 data 字段,失败时抛出错误信息
657
691
  */
658
692
  }, {
659
693
  key: "uploadFile",
660
694
  value: function uploadFile(url, filePath, formData) {
661
695
  var name = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'file';
662
696
  var header = arguments.length > 4 ? arguments[4] : undefined;
697
+ var onProgressUpdateCallback = arguments.length > 5 ? arguments[5] : undefined;
663
698
  return this.request({
664
699
  url: url,
665
700
  filePath: filePath,
@@ -667,7 +702,8 @@
667
702
  name: name,
668
703
  header: header,
669
704
  timeout: this.uploadTimeout,
670
- method: 'POST'
705
+ method: 'POST',
706
+ onProgressUpdateCallback: onProgressUpdateCallback
671
707
  }, uploadFilePromise);
672
708
  }
673
709
  }]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uniapp-request-sdk",
3
- "version": "1.5.1",
3
+ "version": "1.6.1",
4
4
  "description": "用于uniapp小程序的请求库的sdk",
5
5
  "main": "dist/index.umd.js",
6
6
  "module": " dist/index.esm.js",