uni.uploadFile在App端不支持断点续传,因其底层调用原生接口且无法获取上传进度或控制分片;必须使用plus.uploader实现可控分片上传,并配合服务端校验与合并。

uni.uploadFile 在 App 端不支持断点续传
uni.uploadFile 是 uni-app 官方推荐的上传 API,但它在 App 端(iOS/Android)底层调用的是原生 upload 接口,不暴露分片、暂停、恢复等控制能力,也无法获取已上传字节偏移量。这意味着:一旦网络中断或用户切后台,整个上传任务失败,必须重头开始。
常见错误现象:uploadFile 返回 fail abort 或静默失败后无回调;调试器里看到请求被系统 kill,但 JS 层收不到进度或错误细节。
- App 端无法监听原生上传的实时字节进度(H5 可以,但 App 不行)
- 没有
onHeadersReceived或onUploadProgress的可靠实现 - 即使加了
timeout,超时后也无法拿到已上传多少字节
用 plus.uploader 实现可控分片上传
App 端真正能落地断点续传的,只有 plus.uploader —— 这是 5+ Runtime 提供的底层上传模块,支持手动分片、设置请求头、监听每一片的上传状态,并可持久化记录已上传块。
使用场景:单文件 > 10MB、弱网环境(如地铁、电梯)、用户可能频繁切后台的 App。
- 必须用
plus.uploader.createUpload创建实例,不能混用uni.uploadFile - 分片大小建议设为
2 * 1024 * 1024(2MB),太小增加 HTTP 开销,太大重试成本高 - 每片需携带唯一标识(如
partNo=1)和总片数(totalParts=5),服务端据此合并 - 上传前先发一个预检请求(
GET /upload?fileId=xxx&partNo=1),查服务端是否已有该片,跳过已传成功的
示例关键片段:
const uploader = plus.uploader.createUpload('https://api.example.com/upload', {
method: 'POST',
headers: { 'X-Part-Number': '1', 'X-File-Id': 'abc123' }
}, (s, status) => {
if (status === 200) {
console.log('第1片上传成功');
}
});断点状态必须本地持久化,且防多实例冲突
App 切后台后 JS 上下文可能被回收,uploader 实例不可靠。断点信息(如“fileId=abc123 已传完 1/5、3/5”)必须写入本地存储,并加锁避免多个上传任务同时读写同一文件记录。
容易踩的坑:
- 用
uni.setStorageSync存状态,但没做 JSON 序列化/反序列化,存进去是[object Object] - 没加时间戳或版本号,旧状态覆盖新上传进度(比如用户删了 App 又重装,但服务端还有旧分片)
- 多个大文件并发上传时共用同一
fileId,导致状态错乱 - 没在
plus.runtime.quit或plus.app.onPause里主动 flush 状态,切后台瞬间丢进度
服务端必须支持分片校验与合并,不能只靠前端
前端再严谨,服务端不配合也白搭。断点续传不是“前端传一半,下次接着传”,而是“前端传 N 片,服务端确认每片 MD5,最后合并”。否则会出现:
- 中间某片被篡改或损坏,合并后文件打不开
- 重复上传同一片,服务端未去重,磁盘爆满
- 合并逻辑写死路径,没校验分片总数和顺序,导致花屏/音频卡顿
关键要求:
- 接收每片时校验
Content-MD5或额外传X-Part-MD5头 - 返回
200 OK前确保该片落盘并 fsync - 合并接口需带
fileId和签名,防止恶意触发他人合并
别指望前端传个“resumeToken”就让服务端自动续——token 只是索引,真正靠的是每一片的原子性确认。
最常被忽略的一点:App 端上传走的是原生 HTTP 栈,不经过 WebView 的 Cookie 或 uni.getStorage 持有的 token。所有鉴权信息(如 Authorization)必须显式塞进 headers,且要考虑 token 过期重刷问题——这和 H5 完全是两套生命周期。

















