移动端请求重试需精准策略:仅对网络错误及5xx服务端错误重试,采用指数退避+抖动(如500ms→1s→2s+随机200ms),限2~3次;结合abortcontroller防堆积,并在ui层提供渐进式反馈与降级路径。

移动端网络环境复杂多变:WiFi切换、4G/5G信号波动、弱网丢包、后台进程被系统限制等,都会导致请求失败。单纯依赖一次 fetch 或 axios 调用,在移动端极易出现白屏、按钮无响应、数据加载中断等问题。用请求重试机制不是“多试几次”,而是有策略地应对临时性故障,让应用在不稳定的网络中依然可感知、可恢复、不卡死。
只对可重试错误重试,避免无效循环
移动端用户操作敏感,重试必须精准判断错误类型,否则可能把 401(未登录)或 400(参数错)也反复重发,既浪费流量又误导用户。
- ✅ 该重试的:
ERR_NETWORK、ECONNABORTED(超时)、503 Service Unavailable、504 Gateway Timeout、5xx响应(尤其服务端返回Retry-After头时) - ❌ 不该重试的:
400、401、403、404、422等客户端问题;非幂等请求(如POST /order)首次失败后,除非服务端明确支持幂等(带Idempotency-Key),否则不自动重试
用指数退避 + 抖动控制重试节奏
连续重试会加剧弱网拥塞,还可能触发服务端限流。移动端更需“缓一缓再试”:
- 延迟按
baseDelay × 2^attempt增长(如 500ms → 1s → 2s → 4s) - 加入
Math.random() * 200毫秒抖动,避免大量设备在同一时刻重试(防止“重试风暴”) - 最大重试次数建议设为 2~3 次(用户等待容忍度低,4s 内应有反馈)
结合 AbortController 防止请求堆积
用户快速连点按钮、页面快速切换时,旧请求可能还在 pending,新请求已发出。若不清理,会累积大量无效请求,耗电、占内存、干扰真实响应。
- 每次发起请求前创建新的
AbortController - 在请求完成或重试结束时调用
controller.abort()清理未完成任务 - 若用户离开当前页(如
beforeunload或 VueonBeforeUnmount),主动中止所有待处理请求
在 UI 层提供轻量反馈与降级路径
重试是后台逻辑,但用户需要感知:“正在重试”比“没反应”更安心,“重试失败”比“空白页”更可控。
- 请求中显示加载态(如骨架屏或旋转图标),避免按钮重复点击
- 第一次失败后可静默重试(不弹 Toast);第二次失败提示“网络不稳定,正在重试…”;第三次失败给出明确操作入口(如“重试”按钮或“离线缓存内容”)
- 对非关键请求(如埋点、头像预加载),失败直接忽略,不阻塞主流程
示例:Vue 组合式 API 中封装可取消、带退避的请求
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
import { ref, onUnmounted } from 'vue'
import { useTimeoutFn } from '@vueuse/core'
export function useRetriableFetch(url, options = {}) {
const loading = ref(false)
const error = ref(null)
const controller = ref(null)
const execute = async (maxRetries = 2, baseDelay = 500) => {
loading.value = true
error.value = null
controller.value = new AbortController()
for (let attempt = 0; attempt = 500 && ![501, 505].includes(res.status)) {
throw new Error(`HTTP ${res.status}`)
}
return res
} catch (err) {
if (attempt === maxRetries) throw err
const delay = baseDelay * Math.pow(2, attempt) + Math.random() * 200
await new Promise(resolve => setTimeout(resolve, delay))
}
}
}
onUnmounted(() => {
controller.value?.abort()
})
return { loading, error, execute }
}
不复杂但容易忽略——重试不是补丁,而是移动体验的底层韧性设计。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










