重试机制需确保失败可识别、状态可恢复、重试不重复:准确捕获错误类型(网络中断立即重试、超时延迟重试、服务端拒绝先刷新凭证)、绑定任务上下文、添加唯一uploadid防重复、ui统一反馈且支持中断续传。

重试机制不是加个循环就能跑通的,关键得让失败可识别、状态可恢复、重试不重复。
uni.uploadFile 失败时如何准确捕获错误类型
uni.uploadFile 的 fail 回调只返回一个错误对象,但不同失败原因需要不同处理策略:
-
err.errMsg === "uploadFile:fail network error":典型网络中断,适合立即重试(最多 2 次) -
err.errMsg.includes("timeout"):请求超时,建议延迟 1–3 秒再试,避免雪崩 -
uploadRes.statusCode !== 200(在success中判断):服务端拒绝,比如 token 过期、文件类型不符,这类不能盲目重试,要先刷新凭证或提示用户 - 安卓真机上偶尔出现
"uploadFile:fail file not found":大概率是临时路径失效,必须重新uni.chooseImage,不能重试原路径
重试逻辑必须绑定上传任务上下文
单纯对 uni.uploadFile 做 try-catch + for 循环会出问题——每次重试都用同一个 filePath,而这个路径在安卓上可能已失效。正确做法是把上传参数封装成可复用的任务对象:
const uploadTask = {
filePath: tempFilePath,
url: 'https://api.example.com/upload',
name: 'file',
formData: { token: this.token, timestamp: Date.now() },
retryCount: 0,
maxRetry: 3
}
重试时检查 uploadTask.retryCount,失败后递增并调用同一套上传逻辑(含平台路径校验),而不是裸写 uni.uploadFile(...) 三次。
避免重复上传的核心:给每次请求打唯一指纹
服务端没做幂等性处理时,前端重试会导致同一张图被存两份。解决方案是在 formData 里塞一个稳定 ID:
- 用文件哈希(如 MD5)——需引入轻量库,适合大图但增加首屏体积
- 用
tempFilePath + size + lastModified拼接后取 hash(简单够用) - 更推荐:上传前生成
uploadId: Math.random().toString(36).slice(2, 10),和服务端约定该字段用于去重
服务端收到重复 uploadId 直接返回已有结果,前端就不用管“这次到底算成功还是重试”。
用户感知层:重试不能静默,但也不能打断流程
用户点一次上传,背后可能重试 2 次,但 UI 上只该显示一次“上传中 → 成功/失败”:
- 用
uni.showLoading控制全局 loading,首次触发开启,最后一次结果才关闭 - 进度条不要重置,
@progress事件里用累计上传字节数 / 总大小计算真实进度 - 失败后弹 toast 提示“正在重试…(1/3)”,而不是“上传失败,请重试”——后者等于把问题甩给用户
真正容易被忽略的是:重试期间用户如果切换页面或切后台,当前任务必须能暂停或续传,否则既浪费流量又破坏状态一致性。这已经超出简单重试范畴,得配合分片上传和本地状态持久化才能闭环。











