{"id":18938230,"url":"https://github.com/wechat-miniprogram/miniprogram-file-uploader","last_synced_at":"2025-04-15T19:30:22.181Z","repository":{"id":50424263,"uuid":"277458602","full_name":"wechat-miniprogram/miniprogram-file-uploader","owner":"wechat-miniprogram","description":null,"archived":true,"fork":false,"pushed_at":"2024-12-09T12:32:39.000Z","size":78,"stargazers_count":61,"open_issues_count":12,"forks_count":17,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-12T14:51:01.355Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wechat-miniprogram.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-07-06T06:17:48.000Z","updated_at":"2025-03-28T15:09:09.000Z","dependencies_parsed_at":"2022-09-26T20:20:34.039Z","dependency_job_id":null,"html_url":"https://github.com/wechat-miniprogram/miniprogram-file-uploader","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wechat-miniprogram%2Fminiprogram-file-uploader","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wechat-miniprogram%2Fminiprogram-file-uploader/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wechat-miniprogram%2Fminiprogram-file-uploader/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wechat-miniprogram%2Fminiprogram-file-uploader/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wechat-miniprogram","download_url":"https://codeload.github.com/wechat-miniprogram/miniprogram-file-uploader/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249138490,"owners_count":21218896,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-08T12:13:49.945Z","updated_at":"2025-04-15T19:30:21.913Z","avatar_url":"https://github.com/wechat-miniprogram.png","language":"JavaScript","readme":"# miniprogram-file-uploader\n\n小程序大文件上传库。\n\n小程序中的上传文件 [`wx.uploadFile`](https://developers.weixin.qq.com/miniprogram/dev/api/network/upload/wx.uploadFile.html) 接口有大小限制（10M），采用分块上传的方式进行解决。该上传库依赖 [`FileSystemManager.readFile`](https://developers.weixin.qq.com/miniprogram/dev/api/file/FileSystemManager.readFile.html) 接口进行文件的分块读取，基础库版本 `2.10.0` 及以上支持，可通过 `isSupport` 接口判断。\n\n## 支持的特性\n\n* [x] 分块读取，可限制占用内存大小\n* [x] 分块并发上传\n* [x] 支持暂停、恢复、取消、重传\n* [x] 支持秒传，计算md5判断服务端是否已存在\n* [x] 支持进度、预估剩余时间、平均速度、出错自动重试\n* [x] 错误处理\n\n## 安装\n\n通过 `npm` 安装\n\n```bash\nnpm i miniprogram-file-uploader\n```\n\n## 使用\n\n创建一个 `uploader` 实例：\n\n```js\n\nif (Uploader.isSupport()) {\n  const uploader = new Uploader({\n    tempFilePath,\n    totalSize: size,\n    uploadUrl: UPLOAD_URL,\n    mergeUrl: MERGE_URL,\n  })\n\n  uploader.upload()\n}\n```\n\n实例化后可以选择监听一些事件：\n\n```js\n// 成功或失败都会触发\nuploader.on('complete', (res) =\u003e {\n  console.log('upload complete', res)\n})\n\n// 文件上传成功\nuploader.on('success', (res) =\u003e {\n  console.log('upload success', res)\n})\n\n// 文件上传失败\nuploader.on('fail', (res) =\u003e {\n  console.log('fail', res)\n})\n\n// 文件进度变化\nuploader.on('progress', (res) =\u003e {\n  this.setData({\n    progress: res.progress,\n    uploadedSize: parseInt(res.uploadedSize / 1024),\n    averageSpeed: parseInt(res.averageSpeed / 1000),\n    timeRemaining: res.timeRemaining\n  })\n})\n```\n\n## 服务端如何接收\n\n由于小程序端采用分块上传，服务端也需要进行秒传验证、接收分块、分块合并等处理，可参考 `example/server/app.js` 的实现，共涉及到三个接口：\n\n1. 秒传验证 (`verifyUrl: Get`)\n\n当配置项 `testChunks` 为 `true` 时，小程序端会预先发送一个验证请求，利用 `spark-md5` 根据文件内容计算出唯一标识，服务端可根据该值判断是否已经上传，或者上传了部分分片，并返回给前端。小程序端依此可以实现续传或秒传的效果。需注意的是，计算文件的 `hash` 值也有一定的时间和内存损耗。\n\n#### 请求参数\n\n| 属性       | 类型   | 说明          |\n| ---------- | ------ | ------------- |\n| identifier | `String` | 文件的 md5 值 |\n| fileName   | `String` | 文件名        |\n\n#### 返回参数\n\n| 属性           | 类型    | 说明                               |\n| -------------- | ------- | ---------------------------------- |\n| url            | `String`  | 已上传时返回线上文件路径             |\n| needUpload     | `Boolean` | 是否需要上传                       |\n| uploadedChunks | `Array\u003cNumber\u003e`   | 未完全上传时，返回已上传的分块序号 |\n\n2. 接收分块 (`uploadUrl: Post`)\n\n小程序端采用 [`wx.request`](https://developers.weixin.qq.com/miniprogram/dev/api/network/request/wx.request.html) 接口发送文件的二进制数据，`content-type` 为 `application/octet-stream`，服务端接收后放入暂存区，收到合并请求后进行合并。\n\n上传接口的 `query` 中包含如下分块信息：\n\n* `identifier`：文件的唯一标识\n* `index`：分块的序号，从 0 开始\n* `chunkSize`： 分块大小，最后一块可能小于该值\n* `fileName`：文件名，传入的文件名\n* `totalChunks`：分块的总数量，依据 `chunkSize` 计算\n* `totalSize`：文件总大小\n\n3. 合并分块 (`mergeUrl: Get`)\n\n分块全部发送后，小程序端发送合并请求，服务端按分片序号进行合并，返回最终的文件线上路径。\n\n#### 请求参数\n\n| 属性       | 类型   | 说明          |\n| ---------- | ------ | ------------- |\n| identifier | `String` | 文件的 md5 值 |\n| fileName   | `String` | 文件名        |\n\n#### 返回参数\n\n| 属性 | 类型     | 说明         |\n| ---- | -------- | ------------ |\n| url  | `String` | 线上文件路径 |\n\n对于每个请求，小程序端依据配置 `successStatus` 、 `failStatus` 和返回的 `statusCode` 判断成功或失败。\n\n* `200`, `201`, `202`: 请求成功\n* `404`, `415`, `500`, `501`: 请求失败，会终止文件上传\n* 其他状态码: 出错了，但是会自动重试\n\n## API 文档\n\n### Uploader\n\n#### 配置项\n\n实例化的时候可以传入配置项：\n\n```js\nconst uploader = new Uploader(option)\n```\n| 配置项             | 必填 | 类型    | 说明                                                                               |\n| ------------------ | ---- | ------- | ---------------------------------------------------------------------------------- |\n| tempFilePath       | 是   | String  | 小程序内的文件临时路径                                                             |\n| totalSize          | 是   | Number  | 文件的总大小，单位 B                                                               |\n| verifyUrl          | 否   | String  | 秒传验证接口                                                                       |\n| uploadUrl          | 是   | String  | 接收分块接口                                                                       |\n| mergeUrl           | 是   | String  | 合并分块接口                                                                       |\n| maxConcurrency     | 否   | Number  | 并发上传数，默认 5，最大不超过 10                                                  |\n| generateIdentifier | 否   | Function | 可覆盖默认的生成文件唯一标识的函数，需返回 identifier                                |\n| chunkSize          | 否   | Number  | 分块大小，默认 5 * 1024 * 1204 B                                                   |\n| maxMemory          | 否   | Number  | 加载文件最大占用的内存，默认 100 * 1024 * 1024 B，内存占用过大时可能导致小程序闪退 |\n| query              | 否   | Object  | 上传分块时可添加自定义的参数                                                       |\n| header             | 否   | Object  | 上传分块时可添加自定义的请求头                                                     |\n| testChunks         | 否   | Boolean | 是否需要进行秒传验证，默认为 false                                                 |\n| maxChunkRetries    | 否   | Number  | 请求失败时最大重试次数，默认为 0                                                   |\n| chunkRetryInterval | 否   | Number  | 自动重试间隔，默认为 0                                                             |\n| timeout            | 否   | Number  | 请求超时时间，默认 10000 ms                                                        |\n| successStatus      | 否   | Array   | 认为响应式成功的响应码，默认 [200, 201, 202]                                       |\n| failStatus         | 否   | Array   | 认为是出错的响应码，默认 [404, 415, 500, 501]                                      |\n| verbose            | 否   | Boolean | 是否输出开始日志，默认 false                                                       |\n\n\n#### 方法\n\n* .on(event, callback) 监听事件\n* .off(event, callback) 移除事件监听\n* .upload() 开始上传\n* .pause() 暂停上传\n* .resume() 继续上传，与 `pause` 配对使用\n* .cancel() 取消所有上传文件，与 `upload` 配对使用\n* .isSupport() 当前小程序版本是否支持\n\n#### 事件\n\n通过 `on` 方法进行监听\n\n* `success`，上传成功时触发，`e = {errCode: 0, url: 'xxx'}`\n* `fail`，上传失败时触发，`e = {errCode: 0, errMsg: 'xxx'}`\n* `complete`，上传成功或失败时触发，返回值同 `success` 或 `fail`\n* `retry`，请求重传时触发，`e = {statusCode: 302, url: 'xxx'}`\n* `progess`，上传进度变化时触发，返回内容如下：\n\n| 属性          | 类型   | 说明                    |\n| ------------- | ------ | ----------------------- |\n| totalSize     | Number | 文件的总大小，单位 B    |\n| progress      | Number | 上传进度，范围 [0, 100] |\n| uploadedSize  | Number | 已上传大小，单位 B      |\n| averageSpeed  | Number | 平均速度，单位 B/s      |\n| timeRemaining | Number | 预估剩余时间，单位 ms   |\n\n## 注意事项\n\n1. 由于 `wx.requst` 没有 `progressUpdate` 事件，这里的 `progress` 事件在收到分块请求结果后触发；\n2. 真机 `chooseVideo` 返回的临时文件，每次计算 md5 值不同，无法使用秒传功能；\n3. 真机缺少 `console.timeEnd` 方法，部分开发日志会打印不出来；\n\n## 开发\n\n```js\n# 安装依赖\nnpm install\n\n# 启动 example 中的服务，监听文件改动\nnpm run dev\n\n# 编译\nnpm run build\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwechat-miniprogram%2Fminiprogram-file-uploader","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwechat-miniprogram%2Fminiprogram-file-uploader","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwechat-miniprogram%2Fminiprogram-file-uploader/lists"}