uniapp-request-sdk 1.6.1 → 1.7.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.
- package/README.md +498 -4
- package/dist/index.d.ts +152 -26
- package/dist/index.esm.js +185 -21
- package/dist/index.umd.js +185 -21
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
- [详细配置](#详细配置)
|
|
17
17
|
- [API 文档](#api-文档)
|
|
18
18
|
- [文件上传](#文件上传)
|
|
19
|
+
- [文件下载](#文件下载)
|
|
19
20
|
- [使用示例](#使用示例)
|
|
20
21
|
- [响应格式](#响应格式)
|
|
21
22
|
- [错误处理](#错误处理)
|
|
@@ -31,11 +32,12 @@
|
|
|
31
32
|
|
|
32
33
|
这个 SDK 适合以下场景:
|
|
33
34
|
|
|
34
|
-
- uni-app 项目中统一封装 `GET`、`POST`、`PUT`、`DELETE`、`uploadFile`
|
|
35
|
+
- uni-app 项目中统一封装 `GET`、`POST`、`PUT`、`DELETE`、`uploadFile`、`downloadFile`
|
|
35
36
|
- 需要自动处理 `403` 后重新获取 token 再重试的业务场景
|
|
36
37
|
- 需要为所有请求统一追加公共请求头、日志字段、签名字段
|
|
37
38
|
- 需要在 App、小程序、H5 等多端尽量复用一套网络层逻辑
|
|
38
39
|
- 需要在上传文件时监听进度并驱动页面上的进度条展示
|
|
40
|
+
- 需要在下载文件时监听进度并驱动页面上的下载进度条展示
|
|
39
41
|
|
|
40
42
|
如果你的服务端返回结构不是本文档中的默认格式,也可以基于当前 SDK 继续二次封装。
|
|
41
43
|
|
|
@@ -46,6 +48,7 @@
|
|
|
46
48
|
- 支持同步或异步的请求头预处理器 `headerProcessor`
|
|
47
49
|
- 支持 `401`、`403`、网络异常、超时等通用场景处理
|
|
48
50
|
- 支持文件上传、上传超时控制和上传进度监听
|
|
51
|
+
- 支持文件下载、下载超时控制和下载进度监听
|
|
49
52
|
- 默认兼容相对路径与完整 URL 两种调用方式
|
|
50
53
|
|
|
51
54
|
## 特性
|
|
@@ -54,9 +57,10 @@
|
|
|
54
57
|
- ✅ **动态 Token 管理** - 支持自动获取和更新 token,兼容 APP 原生交互
|
|
55
58
|
- ✅ **请求头预处理** - 支持同步/异步预处理器,动态生成或修改请求头
|
|
56
59
|
- ✅ **完整的异常处理** - 统一的错误处理、HTTP 状态码处理、权限管理
|
|
57
|
-
- ✅ **文件上传支持** -
|
|
60
|
+
- ✅ **文件上传支持** - 专门优化的文件上传接口,独立超时控制,进度监听
|
|
61
|
+
- ✅ **文件下载支持** - 专门优化的文件下载接口,独立超时控制,进度监听
|
|
58
62
|
- ✅ **平台兼容** - 支持 iOS App、Android App、H5 等多平台
|
|
59
|
-
- ✅ **TypeScript 支持** -
|
|
63
|
+
- ✅ **TypeScript 支持** - 完整的类型定义和 JSDoc 注释,更好的开发体验
|
|
60
64
|
- ✅ **完全向后兼容** - 不破坏现有代码,渐进式增强
|
|
61
65
|
|
|
62
66
|
## 安装
|
|
@@ -82,6 +86,7 @@ const request = new UniRequest({
|
|
|
82
86
|
baseUrl: 'https://api.example.com',
|
|
83
87
|
timeout: 10000,
|
|
84
88
|
uploadTimeout: 30000,
|
|
89
|
+
downloadTimeout: 30000,
|
|
85
90
|
tokenHeader: 'Authorization',
|
|
86
91
|
tokenPrefix: 'Bearer ',
|
|
87
92
|
onErrorHandler: (error) => {
|
|
@@ -115,6 +120,17 @@ export function uploadAvatar(filePath: string) {
|
|
|
115
120
|
},
|
|
116
121
|
);
|
|
117
122
|
}
|
|
123
|
+
|
|
124
|
+
export function downloadDocument(documentId: string) {
|
|
125
|
+
return request.downloadFile(
|
|
126
|
+
`/documents/${documentId}/download`,
|
|
127
|
+
undefined,
|
|
128
|
+
undefined,
|
|
129
|
+
(progress) => {
|
|
130
|
+
console.log('下载进度:', progress.progress);
|
|
131
|
+
},
|
|
132
|
+
);
|
|
133
|
+
}
|
|
118
134
|
```
|
|
119
135
|
|
|
120
136
|
完成以上两步后,你的工程已经具备:
|
|
@@ -123,6 +139,8 @@ export function uploadAvatar(filePath: string) {
|
|
|
123
139
|
- 统一错误处理能力
|
|
124
140
|
- 文件上传能力
|
|
125
141
|
- 上传进度监听能力
|
|
142
|
+
- 文件下载能力
|
|
143
|
+
- 下载进度监听能力
|
|
126
144
|
|
|
127
145
|
## 快速开始
|
|
128
146
|
|
|
@@ -160,6 +178,16 @@ const uploadResult = await request.uploadFile(
|
|
|
160
178
|
console.log('当前上传进度:', progress.progress);
|
|
161
179
|
},
|
|
162
180
|
);
|
|
181
|
+
|
|
182
|
+
// 7. 下载文件
|
|
183
|
+
const downloadPath = await request.downloadFile(
|
|
184
|
+
'/download/document.pdf',
|
|
185
|
+
undefined,
|
|
186
|
+
undefined,
|
|
187
|
+
(progress) => {
|
|
188
|
+
console.log('当前下载进度:', progress.progress);
|
|
189
|
+
},
|
|
190
|
+
);
|
|
163
191
|
```
|
|
164
192
|
|
|
165
193
|
## 工程接入建议
|
|
@@ -357,6 +385,40 @@ const result = await request.uploadFile<ResponseType>(
|
|
|
357
385
|
);
|
|
358
386
|
```
|
|
359
387
|
|
|
388
|
+
### 文件下载
|
|
389
|
+
|
|
390
|
+
```typescript
|
|
391
|
+
// 基础文件下载
|
|
392
|
+
const tempFilePath = await request.downloadFile('/download/file.pdf');
|
|
393
|
+
|
|
394
|
+
// 带自定义保存路径的下载(仅小程序有效)
|
|
395
|
+
const filePath = await request.downloadFile(
|
|
396
|
+
'/download/file.pdf',
|
|
397
|
+
'user_documents/file.pdf' // 本地保存路径(仅小程序平台支持)
|
|
398
|
+
);
|
|
399
|
+
|
|
400
|
+
// 自定义请求头的下载
|
|
401
|
+
const filePath = await request.downloadFile(
|
|
402
|
+
'/download/file.pdf',
|
|
403
|
+
undefined, // 保存路径
|
|
404
|
+
{ // 自定义请求头
|
|
405
|
+
'X-Download-Token': 'download-token',
|
|
406
|
+
}
|
|
407
|
+
);
|
|
408
|
+
|
|
409
|
+
// 监听下载进度
|
|
410
|
+
const filePath = await request.downloadFile(
|
|
411
|
+
'/download/large-file.zip',
|
|
412
|
+
undefined,
|
|
413
|
+
undefined,
|
|
414
|
+
(progress) => {
|
|
415
|
+
console.log('下载进度百分比:', progress.progress);
|
|
416
|
+
console.log('已下载字节数:', progress.totalBytesWritten);
|
|
417
|
+
console.log('总字节数:', progress.totalBytesExpectedToWrite);
|
|
418
|
+
}
|
|
419
|
+
);
|
|
420
|
+
```
|
|
421
|
+
|
|
360
422
|
## 文件上传
|
|
361
423
|
|
|
362
424
|
### 方法签名
|
|
@@ -402,9 +464,96 @@ type OnProgressUpdateResult = {
|
|
|
402
464
|
- `onProgressUpdateCallback` 是可选参数,不传时上传行为与旧版本保持一致
|
|
403
465
|
- 如果只想传进度回调、不需要自定义 `header`,第 5 个参数需要显式传 `undefined`
|
|
404
466
|
- 上传接口底层仍然返回 Promise,适合继续用 `await` 或 `.then()`
|
|
405
|
-
-
|
|
467
|
+
- 如果上传过程中发生失败并触发重试,进度回调会按”当前这次上传尝试”的进度继续上报
|
|
406
468
|
- 如果服务端返回的是字符串 JSON,SDK 会自动尝试解析后再取其中的 `data`
|
|
407
469
|
|
|
470
|
+
## 文件下载
|
|
471
|
+
|
|
472
|
+
### 新增功能说明
|
|
473
|
+
|
|
474
|
+
从 v1.6.2 版本开始,SDK 新增了 `downloadFile` 方法,提供与 `uploadFile` 对称的文件下载功能。支持:
|
|
475
|
+
|
|
476
|
+
- ✅ 下载文件到本地临时目录或指定路径
|
|
477
|
+
- ✅ 自定义请求头
|
|
478
|
+
- ✅ 实时下载进度监听
|
|
479
|
+
- ✅ 自动重试、Token 管理等企业级特性
|
|
480
|
+
- ✅ 跨平台兼容(App、小程序、H5)
|
|
481
|
+
|
|
482
|
+
### 方法签名
|
|
483
|
+
|
|
484
|
+
```typescript
|
|
485
|
+
downloadFile<T extends string = string>(
|
|
486
|
+
url: string,
|
|
487
|
+
filePath?: string,
|
|
488
|
+
header?: Record<string, string>,
|
|
489
|
+
onProgressUpdateCallback?: (result: DownloadFileProgressUpdateResult) => void,
|
|
490
|
+
): Promise<T>
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
### 参数说明
|
|
494
|
+
|
|
495
|
+
| 参数 | 类型 | 是否必填 | 说明 |
|
|
496
|
+
|------|------|----------|------|
|
|
497
|
+
| `url` | `string` | 是 | 下载资源的 URL,支持相对路径和完整 URL |
|
|
498
|
+
| `filePath` | `string` | 否 | 文件保存路径(本地路径),仅小程序平台支持;如不指定则保存到临时目录 |
|
|
499
|
+
| `header` | `Record<string, string>` | 否 | 当前下载请求的自定义请求头 |
|
|
500
|
+
| `onProgressUpdateCallback` | `(result) => void` | 否 | 下载进度回调 |
|
|
501
|
+
|
|
502
|
+
### 返回值说明
|
|
503
|
+
|
|
504
|
+
方法返回 Promise,解析为下载文件的临时路径(`tempFilePath`):
|
|
505
|
+
|
|
506
|
+
```typescript
|
|
507
|
+
// 基础用法
|
|
508
|
+
const filePath = await request.downloadFile('/files/document.pdf');
|
|
509
|
+
// filePath 是文件的临时路径,如 '/tmp/file_20240314.pdf'
|
|
510
|
+
|
|
511
|
+
// 支持泛型约束
|
|
512
|
+
const filePath: string = await request.downloadFile<string>('/files/document.pdf');
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
### 下载进度回调说明
|
|
516
|
+
|
|
517
|
+
当传入 `onProgressUpdateCallback` 后,SDK 会在内部调用 `uni.downloadFile()` 返回的 `DownloadTask.onProgressUpdate()` 进行绑定。
|
|
518
|
+
|
|
519
|
+
回调参数结构如下:
|
|
520
|
+
|
|
521
|
+
```typescript
|
|
522
|
+
type DownloadFileProgressUpdateResult = {
|
|
523
|
+
progress?: number; // 下载进度百分比 (0-100)
|
|
524
|
+
totalBytesWritten?: number; // 已下载字节数
|
|
525
|
+
totalBytesExpectedToWrite?: number; // 总字节数
|
|
526
|
+
};
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
### 与上传的区别
|
|
530
|
+
|
|
531
|
+
| 特性 | uploadFile | downloadFile |
|
|
532
|
+
|------|-----------|--------------|
|
|
533
|
+
| 超时默认值 | 5 秒 | 30 秒 |
|
|
534
|
+
| 文件来源 | 本地文件 | 远程 URL |
|
|
535
|
+
| 附加参数 | formData(表单字段) | filePath(保存路径) |
|
|
536
|
+
| 进度类型 | `totalBytesSent` | `totalBytesWritten` |
|
|
537
|
+
| 返回值 | 服务端响应的 data 字段 | 文件临时路径 |
|
|
538
|
+
|
|
539
|
+
### 平台兼容性
|
|
540
|
+
|
|
541
|
+
| 特性 | iOS App | Android App | 小程序 | H5 |
|
|
542
|
+
|------|---------|-----------|--------|-----|
|
|
543
|
+
| 基础下载 | ✅ | ✅ | ✅ | ✅ |
|
|
544
|
+
| 进度监听 | ✅ | ✅ | ✅ | 部分 |
|
|
545
|
+
| 自定义保存路径 | ❌ | ❌ | ✅ | ❌ |
|
|
546
|
+
| 文件 URI | ✅ | ✅ | ✅ | 部分 |
|
|
547
|
+
|
|
548
|
+
### 使用注意事项
|
|
549
|
+
|
|
550
|
+
- 下载的文件保存在临时目录,应用关闭后会被清理,需要持久化时调用 `uni.saveFile()`
|
|
551
|
+
- 小程序平台支持指定 `filePath` 保存到指定目录,其他平台会忽略此参数
|
|
552
|
+
- 下载超时时间默认为 30 秒,可通过 `downloadTimeout` 配置修改
|
|
553
|
+
- 下载过程中如果失败,SDK 会自动重试(最多 `maxRetryCount` 次)
|
|
554
|
+
- 下载大文件时建议增加 `downloadTimeout` 的值
|
|
555
|
+
- 下载过程中用户可以通过返回的 Promise 的 abort 功能中止下载(需要获取 DownloadTask)
|
|
556
|
+
|
|
408
557
|
## 使用示例
|
|
409
558
|
|
|
410
559
|
### 示例 1:基础请求
|
|
@@ -557,6 +706,234 @@ async function selectAndUploadFile() {
|
|
|
557
706
|
}
|
|
558
707
|
```
|
|
559
708
|
|
|
709
|
+
### 示例 4-2:文件下载(新增)
|
|
710
|
+
|
|
711
|
+
```typescript
|
|
712
|
+
import UniRequest from 'uniapp-request-sdk';
|
|
713
|
+
|
|
714
|
+
const request = new UniRequest({
|
|
715
|
+
baseUrl: 'https://api.example.com',
|
|
716
|
+
downloadTimeout: 30000, // 文件下载超时 30 秒
|
|
717
|
+
});
|
|
718
|
+
|
|
719
|
+
// 简单下载
|
|
720
|
+
async function downloadFile() {
|
|
721
|
+
try {
|
|
722
|
+
const filePath = await request.downloadFile('/files/document.pdf');
|
|
723
|
+
console.log('下载完成,文件路径:', filePath);
|
|
724
|
+
|
|
725
|
+
// 显示文件
|
|
726
|
+
uni.openDocument({
|
|
727
|
+
filePath: filePath,
|
|
728
|
+
showMenu: true,
|
|
729
|
+
});
|
|
730
|
+
} catch (error) {
|
|
731
|
+
console.error('下载失败:', error);
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
// 带进度监听的下载
|
|
736
|
+
async function downloadFileWithProgress() {
|
|
737
|
+
try {
|
|
738
|
+
let downloadProgress = 0;
|
|
739
|
+
|
|
740
|
+
const filePath = await request.downloadFile(
|
|
741
|
+
'/files/large-file.zip',
|
|
742
|
+
undefined,
|
|
743
|
+
undefined,
|
|
744
|
+
(progress) => {
|
|
745
|
+
downloadProgress = progress.progress || 0;
|
|
746
|
+
console.log(`下载进度: ${downloadProgress}%`);
|
|
747
|
+
console.log(`已下载: ${progress.totalBytesWritten} / ${progress.totalBytesExpectedToWrite} 字节`);
|
|
748
|
+
|
|
749
|
+
// 更新 UI 进度条
|
|
750
|
+
// updateProgressBar(downloadProgress);
|
|
751
|
+
}
|
|
752
|
+
);
|
|
753
|
+
|
|
754
|
+
console.log('下载完成:', filePath);
|
|
755
|
+
} catch (error) {
|
|
756
|
+
console.error('下载失败:', error, downloadProgress);
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
// 小程序中下载到指定路径
|
|
761
|
+
async function downloadFileToPath() {
|
|
762
|
+
try {
|
|
763
|
+
const filePath = await request.downloadFile(
|
|
764
|
+
'/files/contract.pdf',
|
|
765
|
+
'user_documents/contract.pdf' // 保存到应用沙箱
|
|
766
|
+
);
|
|
767
|
+
|
|
768
|
+
console.log('文件已保存:', filePath);
|
|
769
|
+
} catch (error) {
|
|
770
|
+
console.error('下载失败:', error);
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
// 带自定义 header 的下载(如需要鉴权)
|
|
775
|
+
async function downloadSecureFile() {
|
|
776
|
+
try {
|
|
777
|
+
const filePath = await request.downloadFile(
|
|
778
|
+
'/files/secure-document.pdf',
|
|
779
|
+
undefined,
|
|
780
|
+
{
|
|
781
|
+
'X-Download-Token': 'secure-token-xxx',
|
|
782
|
+
'X-User-Id': 'user-123',
|
|
783
|
+
},
|
|
784
|
+
(progress) => {
|
|
785
|
+
console.log(`下载进度: ${progress.progress}%`);
|
|
786
|
+
}
|
|
787
|
+
);
|
|
788
|
+
|
|
789
|
+
console.log('下载完成:', filePath);
|
|
790
|
+
} catch (error) {
|
|
791
|
+
console.error('下载失败:', error);
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
```
|
|
795
|
+
|
|
796
|
+
### 示例 4-3:综合文件管理(上传和下载)
|
|
797
|
+
|
|
798
|
+
```typescript
|
|
799
|
+
import UniRequest from 'uniapp-request-sdk';
|
|
800
|
+
|
|
801
|
+
const request = new UniRequest({
|
|
802
|
+
baseUrl: 'https://api.example.com',
|
|
803
|
+
uploadTimeout: 30000,
|
|
804
|
+
downloadTimeout: 30000,
|
|
805
|
+
});
|
|
806
|
+
|
|
807
|
+
// 文件管理服务
|
|
808
|
+
export const FileService = {
|
|
809
|
+
// 上传文件
|
|
810
|
+
uploadDocument: async (filePath: string, metadata: Record<string, any>) => {
|
|
811
|
+
try {
|
|
812
|
+
const result = await request.uploadFile(
|
|
813
|
+
'/documents/upload',
|
|
814
|
+
filePath,
|
|
815
|
+
metadata,
|
|
816
|
+
'file',
|
|
817
|
+
undefined,
|
|
818
|
+
(progress) => {
|
|
819
|
+
console.log(`上传进度: ${progress.progress}%`);
|
|
820
|
+
}
|
|
821
|
+
);
|
|
822
|
+
return result;
|
|
823
|
+
} catch (error) {
|
|
824
|
+
console.error('上传失败:', error);
|
|
825
|
+
throw error;
|
|
826
|
+
}
|
|
827
|
+
},
|
|
828
|
+
|
|
829
|
+
// 下载文件
|
|
830
|
+
downloadDocument: async (documentId: string, fileName: string) => {
|
|
831
|
+
try {
|
|
832
|
+
const filePath = await request.downloadFile(
|
|
833
|
+
`/documents/download/${documentId}`,
|
|
834
|
+
`downloads/${fileName}`,
|
|
835
|
+
{ 'X-Document-Id': documentId },
|
|
836
|
+
(progress) => {
|
|
837
|
+
console.log(`下载进度: ${progress.progress}%`);
|
|
838
|
+
}
|
|
839
|
+
);
|
|
840
|
+
return filePath;
|
|
841
|
+
} catch (error) {
|
|
842
|
+
console.error('下载失败:', error);
|
|
843
|
+
throw error;
|
|
844
|
+
}
|
|
845
|
+
},
|
|
846
|
+
|
|
847
|
+
// 列出文档
|
|
848
|
+
listDocuments: async (payload: Record<string, any>) => {
|
|
849
|
+
return request.post('/documents/list', payload);
|
|
850
|
+
},
|
|
851
|
+
|
|
852
|
+
// 删除文档
|
|
853
|
+
deleteDocument: async (documentId: string) => {
|
|
854
|
+
return request.delete(`/documents/${documentId}`);
|
|
855
|
+
},
|
|
856
|
+
};
|
|
857
|
+
|
|
858
|
+
// 在组件中使用
|
|
859
|
+
export default {
|
|
860
|
+
data() {
|
|
861
|
+
return {
|
|
862
|
+
uploadProgress: 0,
|
|
863
|
+
downloadProgress: 0,
|
|
864
|
+
documents: [],
|
|
865
|
+
};
|
|
866
|
+
},
|
|
867
|
+
|
|
868
|
+
methods: {
|
|
869
|
+
// 选择并上传文件
|
|
870
|
+
async selectAndUpload() {
|
|
871
|
+
try {
|
|
872
|
+
const res = await uni.chooseFile({
|
|
873
|
+
type: 'file',
|
|
874
|
+
count: 1,
|
|
875
|
+
});
|
|
876
|
+
|
|
877
|
+
const result = await FileService.uploadDocument(
|
|
878
|
+
res.tempFilePaths[0],
|
|
879
|
+
{
|
|
880
|
+
description: '重要文档',
|
|
881
|
+
category: 'reports',
|
|
882
|
+
}
|
|
883
|
+
);
|
|
884
|
+
|
|
885
|
+
uni.showToast({
|
|
886
|
+
title: '上传成功',
|
|
887
|
+
icon: 'success',
|
|
888
|
+
});
|
|
889
|
+
|
|
890
|
+
// 刷新列表
|
|
891
|
+
await this.loadDocuments();
|
|
892
|
+
} catch (error) {
|
|
893
|
+
uni.showToast({
|
|
894
|
+
title: '上传失败',
|
|
895
|
+
icon: 'error',
|
|
896
|
+
});
|
|
897
|
+
}
|
|
898
|
+
},
|
|
899
|
+
|
|
900
|
+
// 下载文件
|
|
901
|
+
async downloadDocument(documentId: string, fileName: string) {
|
|
902
|
+
try {
|
|
903
|
+
const filePath = await FileService.downloadDocument(documentId, fileName);
|
|
904
|
+
|
|
905
|
+
// 打开文件
|
|
906
|
+
uni.openDocument({
|
|
907
|
+
filePath: filePath,
|
|
908
|
+
showMenu: true,
|
|
909
|
+
});
|
|
910
|
+
} catch (error) {
|
|
911
|
+
uni.showToast({
|
|
912
|
+
title: '下载失败',
|
|
913
|
+
icon: 'error',
|
|
914
|
+
});
|
|
915
|
+
}
|
|
916
|
+
},
|
|
917
|
+
|
|
918
|
+
// 加载文档列表
|
|
919
|
+
async loadDocuments() {
|
|
920
|
+
try {
|
|
921
|
+
this.documents = await FileService.listDocuments({
|
|
922
|
+
page: 1,
|
|
923
|
+
limit: 20,
|
|
924
|
+
});
|
|
925
|
+
} catch (error) {
|
|
926
|
+
console.error('加载失败:', error);
|
|
927
|
+
}
|
|
928
|
+
},
|
|
929
|
+
},
|
|
930
|
+
|
|
931
|
+
mounted() {
|
|
932
|
+
this.loadDocuments();
|
|
933
|
+
},
|
|
934
|
+
};
|
|
935
|
+
```
|
|
936
|
+
|
|
560
937
|
### 示例 5:实时生成签名
|
|
561
938
|
|
|
562
939
|
```typescript
|
|
@@ -1231,6 +1608,97 @@ await Promise.all(
|
|
|
1231
1608
|
);
|
|
1232
1609
|
```
|
|
1233
1610
|
|
|
1611
|
+
### Q: 如何下载多个文件?
|
|
1612
|
+
|
|
1613
|
+
A: 需要多次调用 `downloadFile`,建议使用串行下载避免超时:
|
|
1614
|
+
|
|
1615
|
+
```typescript
|
|
1616
|
+
// 方式 1:顺序下载(推荐)
|
|
1617
|
+
const filePaths = [];
|
|
1618
|
+
for (const fileUrl of fileUrls) {
|
|
1619
|
+
const path = await request.downloadFile(fileUrl);
|
|
1620
|
+
filePaths.push(path);
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1623
|
+
// 方式 2:并行下载(需谨慎,可能导致超时)
|
|
1624
|
+
const filePaths = await Promise.all(
|
|
1625
|
+
fileUrls.map(fileUrl => request.downloadFile(fileUrl))
|
|
1626
|
+
);
|
|
1627
|
+
```
|
|
1628
|
+
|
|
1629
|
+
### Q: 下载的文件如何持久化?
|
|
1630
|
+
|
|
1631
|
+
A: 使用 `uni.saveFile()` 将临时文件保存到永久目录:
|
|
1632
|
+
|
|
1633
|
+
```typescript
|
|
1634
|
+
const tempFilePath = await request.downloadFile('/file.pdf');
|
|
1635
|
+
|
|
1636
|
+
// 保存到永久位置
|
|
1637
|
+
uni.saveFile({
|
|
1638
|
+
tempFilePath: tempFilePath,
|
|
1639
|
+
success: (res) => {
|
|
1640
|
+
console.log('文件已保存:', res.savedFilePath);
|
|
1641
|
+
},
|
|
1642
|
+
});
|
|
1643
|
+
```
|
|
1644
|
+
|
|
1645
|
+
### Q: 下载大文件时超时怎么办?
|
|
1646
|
+
|
|
1647
|
+
A: 增加 `downloadTimeout` 的值:
|
|
1648
|
+
|
|
1649
|
+
```typescript
|
|
1650
|
+
const request = new UniRequest({
|
|
1651
|
+
baseUrl: 'https://api.example.com',
|
|
1652
|
+
downloadTimeout: 60000, // 60 秒,适合大文件
|
|
1653
|
+
});
|
|
1654
|
+
|
|
1655
|
+
// 或在运行时修改
|
|
1656
|
+
request.setParams({
|
|
1657
|
+
downloadTimeout: 120000, // 120 秒
|
|
1658
|
+
});
|
|
1659
|
+
```
|
|
1660
|
+
|
|
1661
|
+
### Q: 如何取消正在进行的下载?
|
|
1662
|
+
|
|
1663
|
+
A: 目前库返回的是 Promise,无法直接获取 DownloadTask 来调用 abort。建议通过以下方式实现:
|
|
1664
|
+
|
|
1665
|
+
```typescript
|
|
1666
|
+
// 方式 1:修改库的源码返回 DownloadTask(高级用法)
|
|
1667
|
+
// 方式 2:使用超时机制让请求自动中止
|
|
1668
|
+
// 方式 3:在下载进度回调中检查用户是否点击了取消
|
|
1669
|
+
|
|
1670
|
+
// 推荐:在进度回调中检查状态
|
|
1671
|
+
let shouldCancel = false;
|
|
1672
|
+
|
|
1673
|
+
await request.downloadFile(
|
|
1674
|
+
'/file.zip',
|
|
1675
|
+
undefined,
|
|
1676
|
+
undefined,
|
|
1677
|
+
(progress) => {
|
|
1678
|
+
if (shouldCancel) {
|
|
1679
|
+
// 无法直接中止,但可以停止处理
|
|
1680
|
+
return;
|
|
1681
|
+
}
|
|
1682
|
+
console.log(`下载进度: ${progress.progress}%`);
|
|
1683
|
+
}
|
|
1684
|
+
);
|
|
1685
|
+
|
|
1686
|
+
// 用户点击取消按钮时
|
|
1687
|
+
function cancelDownload() {
|
|
1688
|
+
shouldCancel = true;
|
|
1689
|
+
}
|
|
1690
|
+
```
|
|
1691
|
+
|
|
1692
|
+
### Q: 下载的文件在哪里?
|
|
1693
|
+
|
|
1694
|
+
A: 下载的文件保存在以下位置:
|
|
1695
|
+
|
|
1696
|
+
- **H5**: 浏览器默认下载目录
|
|
1697
|
+
- **小程序**: 临时目录(`wx.env.USER_DATA_PATH` 下),或指定的 `filePath`
|
|
1698
|
+
- **App**: 应用的缓存目录
|
|
1699
|
+
|
|
1700
|
+
建议下载后立即使用或保存,避免应用被清理时文件丢失。
|
|
1701
|
+
|
|
1234
1702
|
### Q: 如何处理 token 过期?
|
|
1235
1703
|
|
|
1236
1704
|
A: 库会自动在收到 403 状态码时获取新 token 并重试。如需自定义逻辑:
|
|
@@ -1265,6 +1733,32 @@ A: 是的,包括重试时都会执行。这是为了确保每次请求都获
|
|
|
1265
1733
|
|
|
1266
1734
|
## 版本历史
|
|
1267
1735
|
|
|
1736
|
+
### v1.6.2(最新)
|
|
1737
|
+
|
|
1738
|
+
- ✨ **新增** 文件下载功能 (`downloadFile` 方法)
|
|
1739
|
+
- 支持下载文件到本地目录或临时目录
|
|
1740
|
+
- 支持实时下载进度监听
|
|
1741
|
+
- 支持自定义请求头
|
|
1742
|
+
- 自动继承 token、重试等企业级特性
|
|
1743
|
+
- 默认超时时间 30 秒(可配置)
|
|
1744
|
+
|
|
1745
|
+
- 📝 **文档改进** 完整的 JSDoc 注释
|
|
1746
|
+
- 所有公开/私有方法添加详细 JSDoc
|
|
1747
|
+
- 所有参数和返回值有清晰说明
|
|
1748
|
+
- 关键方法包含使用示例
|
|
1749
|
+
- 100% 注释覆盖率
|
|
1750
|
+
|
|
1751
|
+
- 📚 **README 更新**
|
|
1752
|
+
- 新增《文件下载》文档章节
|
|
1753
|
+
- 新增文件下载的详细使用示例(示例 4-2、4-3)
|
|
1754
|
+
- 更新目录索引
|
|
1755
|
+
- 完善参数和平台兼容性说明
|
|
1756
|
+
|
|
1757
|
+
- 🔧 **技术改进**
|
|
1758
|
+
- 优化 TypeScript 类型定义
|
|
1759
|
+
- 完善错误处理机制
|
|
1760
|
+
- 增强跨平台兼容性检查
|
|
1761
|
+
|
|
1268
1762
|
### v1.4.11
|
|
1269
1763
|
|
|
1270
1764
|
- ✨ **新增** 请求头预处理器功能 (`headerProcessor`)
|