HarmonyOS 网络请求稳定性实战超时、重试、弱网兜底与状态恢复网络请求失败不一定是接口挂了。移动场景里更常见的是弱网抖动、切后台、DNS 延迟、服务端偶发 5xx、用户重复点击、页面销毁后回调仍然更新状态。稳定的网络层不能只封装一个request还要处理超时、错误分类、重试、缓存兜底和页面状态恢复。一、先定义请求上下文请求上下文要包含业务场景、超时、重试次数和缓存策略。这样同一个网络层可以服务不同页面。场景策略首页列表可重试可读缓存提交表单不自动重试避免重复提交搜索建议短超时失败静默详情页可重试失败展示重试按钮二、版本与边界说明本文以 HarmonyOS / ArkTS 网络请求封装为背景示例不绑定具体服务端协议。真实项目可以接入ohos.net.http、团队 HTTP SDK 或网关层但请求上下文、错误映射和恢复策略应保持独立。建议记录以下环境项目说明API 版本当前 HarmonyOS SDK网络库系统 HTTP 或团队封装服务端协议REST、GraphQL 或自定义协议缓存层内存、Preferences、文件或数据库三、请求模型不要只传 URL只传 URL 会让网络层不知道该不该重试、该不该缓存、失败后怎么提示。exportinterfaceRequestContext{id:string;url:string;method:GET|POST|PUT|DELETE;timeoutMs:number;retryTimes:number;cacheKey?:string;scene:list|detail|submit|search;}代码解释scene决定错误提示和恢复策略。retryTimes明确最大重试次数。cacheKey存在时才允许缓存兜底。请求上下文让网络层不再盲目处理。四、错误分类不是所有失败都能重试4xx 多半是客户端参数或权限问题盲目重试没有意义网络断开和 5xx 才更适合重试。exporttypeRequestErrorTypenetwork|timeout|server|client|business;exportfunctioncanRetry(type:RequestErrorType):boolean{returntypenetwork||typetimeout||typeserver;}代码解释错误类型先归类再决定策略。客户端错误不自动重试避免浪费请求。业务错误交给页面显示具体原因。错误分类是稳定请求的基础。五、指数退避重试要克制重试不能立刻连续打三次否则弱网下会加重拥塞。指数退避能给网络恢复时间。exportfunctiongetRetryDelay(attempt:number):number{constbase500;constmax8000;returnMath.min(base*Math.pow(2,attempt),max);}代码解释第一次重试等待较短后续逐步增加。max防止等待时间无限增长。表单提交类请求不建议自动重试。重试策略要和错误分类配合使用。六、缓存兜底失败时保留可用内容列表和详情页可以在请求失败时读取上一次成功缓存让页面不至于空白。exportinterfaceCacheRecordT{value:T;savedAt:number;}exportfunctionisCacheFreshT(record:CacheRecordT,ttlMs:number):boolean{returnDate.now()-record.savedAtttlMs;}代码解释缓存要有时间戳避免长期展示过期数据。ttlMs按业务场景配置。缓存兜底适合展示型数据不适合支付或提交结果。页面要提示“当前为缓存数据”避免误导用户。七、页面状态恢复请求失败也要有确定状态页面状态不能只有成功和加载。弱网下要能表达缓存、失败、重试中和空数据。exporttypePageDataStateidle|loading|success|cacheFallback|failed;exportinterfaceNetworkPageStateT{state:PageDataState;data?:T;message?:string;}代码解释cacheFallback明确说明当前数据来自缓存。failed用于展示重试入口。message给用户可理解的提示。页面状态清楚后弱网体验会稳定很多。八、防止过期回调页面销毁后不更新状态网络请求返回时页面可能已经退出。需要用请求 id 或生命周期标记避免旧回调覆盖新状态。exportclassRequestToken{privateactivetrue;cancel():void{this.activefalse;}canUpdate():boolean{returnthis.active;}}代码解释页面退出时调用cancel。请求回调前检查canUpdate。这样可以避免页面销毁后仍更新状态。搜索、下拉刷新、快速切页都需要类似保护。九、验证流程1. 正常网络打开列表确认请求成功并写入缓存。 2. 切到弱网确认超时和重试策略生效。 3. 断网后进入页面确认可读取缓存兜底。 4. 表单提交失败时确认不会自动重复提交。 5. 快速进入再退出页面确认旧回调不更新 UI。 6. 查看日志确认错误类型和重试次数可追踪。十、常见问题排查现象可能原因修复建议弱网一直转圈没有超时设置timeoutMs重复提交订单POST 自动重试提交类禁用自动重试失败页面空白没有缓存兜底增加cacheFallback返回后崩溃旧回调更新页面加入RequestToken错误提示混乱未分类错误使用RequestErrorType十一、验收清单检查项是否完成请求有超时配置错误类型能区分可重试和不可重试场景分开缓存兜底有过期时间页面销毁后不会更新状态弱网验收要覆盖断网、慢网、请求中切后台、请求中返回上一页。只测正常 Wi-Fi网络层问题基本看不出来。还要看“用户重复触发”。比如用户连续下拉刷新、连续点击提交按钮、搜索框快速输入这些场景会产生多个并发请求。如果没有请求 token、节流或取消机制旧请求可能覆盖新结果页面就会出现数据倒退。十二、工程落地建议可以先从首页列表接入稳定请求链路因为它既需要加载速度也需要弱网兜底。首页跑通后再把详情页、搜索页和提交页按各自策略接入不要所有请求套同一套重试规则。建议把网络请求分成三类治理查询类、提交类、实时类。查询类可以重试和读缓存提交类必须防重复实时类要关注连接状态和恢复策略。分类之后网络层的默认策略才不会误伤业务。上线后可以记录脱敏指标请求耗时、错误类型、重试次数、缓存命中、最终状态。这些指标能帮助团队判断问题到底来自服务端、网络环境还是客户端状态管理。不要只记录“请求失败”那样无法定位。如果服务端支持幂等键提交类请求最好带上业务幂等标识。这样即使用户重复点击或网络层发生重试服务端也能识别同一笔业务操作避免重复创建订单、重复收藏或重复提交表单。弱网兜底也要避免过度乐观。缓存数据应有时间标识页面可以提示“当前展示上次成功加载的数据”。让用户知道数据来源比悄悄展示过期内容更可靠。并发请求也要治理。搜索框输入、筛选条件切换、下拉刷新都可能在短时间内发起多次请求。建议给每个请求带上序号页面只接受最后一次请求的结果。否则旧请求慢一步返回就可能覆盖新数据。exportclassLatestRequestGuard{privatelatestId0;next():number{this.latestId1;returnthis.latestId;}isLatest(id:number):boolean{returnidthis.latestId;}}代码解释每次发起请求前调用next生成新的请求序号。回调返回时用isLatest判断是否仍是最新请求。旧请求结果直接丢弃避免覆盖新页面状态。搜索、筛选、分页刷新都适合接入这个保护。网络层还要和页面生命周期配合。页面退出时不一定能取消底层请求但至少不能让回调继续更新 UI。RequestToken和LatestRequestGuard可以组合使用前者处理页面是否还活着后者处理结果是否过期。对于缓存兜底要区分“可展示缓存”和“可提交缓存”。列表、详情、资讯内容可以展示缓存支付结果、库存状态、权限状态不能随便用旧数据兜底。不同数据类型要有明确规则。发布前还要检查错误文案。网络错误、服务端错误、登录失效、业务失败应该给不同提示。用户看到“网络异常”却实际是登录过期会误判问题也会增加客服成本。错误文案最好和错误类型一一对应避免所有失败都落到同一个 Toast。这会直接影响用户是否愿意再次尝试。十三、总结网络稳定性的核心不是多重试几次而是让请求行为可预测超时有边界、错误能分类、重试有节制、缓存能兜底、页面状态可恢复。做到这些弱网体验才会从“碰运气”变成可治理。