uni-app大文件分片下载必须绕开uni.downloadFile,改用uni.request手动发Range请求或plus.downloader原生模块,且服务端须支持Accept-Ranges和Range头,否则返回416或整包数据。

uni-app大文件分片下载必须绕开uni.downloadFile
直接用uni.downloadFile处理超过10MB的文件,基本会失败——它不支持Range请求,无法断点续传,且在Android上容易触发内存溢出或被系统杀后台。分片下载本质是HTTP协议层操作,必须自己构造带Range头的请求,而uni.downloadFile完全封装了底层逻辑,不可控。真正可行的路径只有两条:uni.request手动发分片请求(需服务端支持Accept-Ranges),或调用plus.downloader原生模块(仅App端可用)。
服务端必须返回Accept-Ranges: bytes且支持Range头
分片下载不是客户端单方面能搞定的事。如果服务端没开启范围请求支持,所有分片请求都会返回416或直接回整个文件,导致重复下载、校验失败。验证方式很简单:
- 用
curl -I https://your-domain.com/file.zip检查响应头是否含Accept-Ranges: bytes - 手动测试:
curl -H "Range: bytes=0-1023" https://your-domain.com/file.zip,看是否返回206 Partial Content和正确Content-Range
常见坑:Nginx默认不开accept_ranges on;CDN(如腾讯云、阿里云)需单独开启“Range回源”;后端框架(如Spring Boot)要确保未禁用HttpServletResponse的分段写入能力。
用uni.request实现分片下载的关键控制点
这是H5和小程序通用方案,但要注意平台限制(微信小程序uni.request不支持responseType: 'arraybuffer',必须用base64中转,性能差;App端可直接用arraybuffer):
- 每个分片请求必须设
header: { Range: `bytes=${start}-${end}` },且responseType设为arraybuffer(App)或text(小程序需再uni.getFileSystemManager().writeFile拼接) - 不能并发过多分片(建议≤3),否则安卓WebView易崩溃;iOS对并发更敏感,需加节流
- 每个分片响应后,用
uni.getFileSystemManager().appendFile追加到目标文件,别用writeFile覆盖——否则前几片就丢了 - 最后必须校验总大小与
Content-Length头一致,避免因服务端缓存或CDN截断导致文件损坏
示例片段(App端):
const fm = uni.getFileSystemManager();
await fm.writeFile({ filePath: finalPath, data: new Uint8Array(0), encoding: 'binary' }); // 初始化空文件
// 分片循环内:
uni.request({
url,
header: { Range: `bytes=${start}-${end}` },
responseType: 'arraybuffer',
success: res => {
fm.appendFile({ filePath: finalPath, data: res.data });
}
});
Android 10+ 和 iOS 的路径与权限陷阱
即使分片下载成功,保存路径不对或权限缺失,用户依然找不到文件:
- Android 10+(API 29+)强制Scoped Storage,
file:///storage/emulated/0/Download/这种路径直接写入会失败,必须用plus.io.resolveLocalFileSystemURL先确认目录可写,或降级加android:requestLegacyExternalStorage="true" - iOS沙盒严格,不能直接写入
Documents外目录;plus.downloader.createDownload生成的路径需以file://开头,且父目录必须存在(plus.io.mkdir提前创建) - 文件名含中文或空格时,Android需
encodeURIComponent,iOS需escape,否则openDocument打不开
最稳做法:App端优先走plus.downloader,它天然支持分片、断点、绝对路径;H5和小程序放弃分片,改用服务端直链+浏览器原生下载;微信小程序则依赖downloadFile + 后端切片代理(即前端只下1个URL,由后端做Range转发)。











