【鸿蒙心迹】HarmonyOS笔记31:网络请求加载态与错误态
HarmonyOS笔记31:网络请求加载态与错误态
🔥 个人主页: 杨利杰YJlio
❄️ 个人专栏: 《Windows 疑难杂症与工单复盘案例库》 《Sysinternals实战教程》
《WINDOWS教程》 《Windows PowerShell 实战》 《IOS插件分析测试》
🌟 让复杂的事情更简单,让重复的工作自动化


文章目录
大家好,我是杨利杰 YJlio。
上一篇我把 HTTP 请求、响应检查和 JSON 字段校验串了起来。这一篇继续往页面层走:请求正在执行时给出加载反馈,请求结束后展示结果;如果请求失败,页面要说明当前状态,并提供明确的重试入口。
本文会先用一个可控的模拟请求观察界面状态,再说明如何把模拟方法替换为上一节的真实网络请求。模拟请求只用于演示界面状态,不代表已经连接服务端或完成设备实测。
一、先把页面状态拆清楚
网络请求页面至少要区分四种状态:
| 状态 | 页面反馈 | 用户此时能做什么 |
|---|---|---|
| idle | 尚未开始请求 | 发起请求 |
| loading | 正在加载 | 等待完成,避免重复提交 |
| success | 展示经过校验的结果 | 查看或继续操作 |
| error | 展示可理解的失败提示 | 检查原因后重试 |

这样拆分,可以避免把“请求已返回”“内容已解析”和“业务处理成功”混成一个标志。请求成功只说明流程到达了某一步,页面是否能展示数据,还要看响应和数据校验是否通过。
加载、成功、失败应当是互斥的页面状态;同一时刻让用户看清当前处于哪一步。
二、四种状态分别显示什么
初始状态可以提示用户点击按钮开始;加载状态显示进度反馈;成功状态显示结果;错误状态则显示面向用户的说明和重试入口。

错误提示不必把堆栈、内部路径或服务端敏感信息直接展示给用户。页面可以给出简短提示,真实错误对象、HTTP状态和请求上下文则按项目日志规范记录,便于开发阶段排查。
如果请求结果为空,也不要把空字符串自动解释成请求失败。是否为空代表业务错误,应由接口契约决定。
三、状态字段怎样分工
在 ArkUI 组件中,界面依赖的数据应使用状态变量。这里把界面状态、成功文本和错误提示分开保存:

viewState负责决定显示哪一块界面;resultText和errorMessage分别保存成功与失败信息;inFlight只是防止重复触发的逻辑保护,不负责驱动页面渲染。
ArkUI 的 @State 用于组件内状态管理,状态变化会触发界面更新。使用条件渲染时,分支依据状态变量选择当前内容。具体写法应以工程当前采用的状态管理方案和 SDK 文档为准。
四、失败不是一种情况
失败可能发生在不同层:设备没有网络、连接或读取超时、服务器返回非预期 HTTP 状态、响应体不是合法 JSON,或者 JSON 中缺少页面需要的字段。它们的排查位置不同,不应全部压缩成“请求失败”后就丢掉诊断信息。

我会把处理分成两层:用户界面给出稳定、易理解的提示;开发诊断保留真实状态码、错误对象和必要的请求上下文。日志内容要符合项目的隐私与安全要求,不记录令牌、密码或不必要的个人数据。
网络异常、HTTP异常、解析异常和业务校验异常要分层判断,页面提示与排障日志也要分开。
五、用模拟请求验证状态流转
为了先观察页面逻辑,可以暂时用一个模拟函数代替网络层。这个函数延迟后按参数返回成功或失败,延迟值只是演示界面过渡的模拟配置,不是网络耗时测量。
function requestSample(shouldFail: boolean): Promise<string> {
return new Promise<string>((resolve, reject) => {
setTimeout(() => {
if (shouldFail) {
reject('模拟请求失败');
} else {
resolve('模拟数据,仅用于UI流程示范');
}
}, 600);
});
}
组件的请求处理负责先切换到加载状态,再等待结果,并在 finally 中恢复防重复标志:
@State viewState: string = 'idle';
@State resultText: string = '';
@State errorMessage: string = '';
private inFlight: boolean = false;
private lastShouldFail: boolean = false;
async loadMessage(shouldFail: boolean): Promise<void> {
if (this.inFlight) {
return;
}
this.inFlight = true;
this.lastShouldFail = shouldFail;
this.viewState = 'loading';
this.resultText = '';
this.errorMessage = '';
try {
this.resultText = await requestSample(shouldFail);
this.viewState = 'success';
} catch (error) {
this.errorMessage = String(error);
this.viewState = 'error';
} finally {
this.inFlight = false;
}
}
在界面事件中分别调用 loadMessage(false) 和 loadMessage(true),可以观察成功与失败分支。重试按钮调用 loadMessage(this.lastShouldFail),表示再次执行上一次的模拟场景;真实项目里应重放必要的请求参数,并考虑请求是否幂等。

这个 inFlight 检查是组件内的重复触发保护,不能代替服务端的幂等设计。对付款、创建订单等有副作用的请求,还应使用业务侧的幂等键或服务端去重策略。
六、按状态做条件渲染
在 build() 中,可以依据 viewState 选择对应内容。下面是结构示意,具体组件属性和导入按当前工程模板确认:
if (this.viewState === 'idle') {
Text('点击按钮开始请求');
} else if (this.viewState === 'loading') {
Text('正在加载,请稍候');
} else if (this.viewState === 'success') {
Text(this.resultText);
} else {
Text(this.errorMessage);
Button('重试').onClick(() => this.loadMessage(this.lastShouldFail));
}

if/else 分支让页面在任一时刻显示与当前状态匹配的内容。实际布局还可以给加载态加入 LoadingProgress,但要先确认目标 SDK 支持的组件和属性;这里不虚构具体运行截图或编译结果。
七、把模拟层替换成真实 HTTP 请求
界面状态处理稳定后,再把 requestSample() 换成 030 篇中的真实请求函数。真实请求函数负责创建 HTTP 请求、检查响应状态与响应体、解析并校验字段,成功时返回可展示的数据,失败时抛出或返回明确的错误。页面层继续负责 loading、success、error 的转换。

请求对象的释放应放在网络函数自身的 finally 中;页面的 inFlight 复位则放在页面方法的 finally 中。两层清理职责不同。finally 能确保函数正常结束或抛错时执行清理,但不等同于用户离开页面后自动取消请求;取消与生命周期管理需要单独设计和验证。
八、练习时按清单核对
把模拟函数接入页面后,先观察四种状态,再接真实接口。每次只改变一个条件,并记录操作步骤、环境和页面表现。

| 检查项 | 操作 | 需要记录的结果 |
|---|---|---|
| 初始状态 | 首次打开页面 | 是否提示可以开始请求 |
| 加载状态 | 触发请求 | 加载反馈是否出现,重复触发是否被拦截 |
| 成功状态 | 使用成功响应 | 页面是否展示校验后的内容 |
| 失败状态 | 断网、超时或构造失败响应 | 提示是否清楚,诊断信息是否保留 |
| 重试 | 失败后再次操作 | 请求参数是否正确,状态是否回到加载态 |
目前这份文章没有本机工程、SDK版本、设备型号或实际运行日志,因此表格结果需要在自己的练习环境中填写。示意图片只解释状态关系,不作为 DevEco Studio 截图或实测证据。
学习总结
这一篇的重点是先定义状态,再让界面跟随状态变化。模拟请求可以帮助我隔离和观察 UI 逻辑;接入真实 HTTP 请求后,还要分别处理网络、HTTP、JSON与业务校验等失败层次。
用状态表达页面当前处境,用 finally 保证流程收尾,再用实际日志验证每条分支。
下一篇预告
下一篇将整理网络权限配置与用户授权流程,区分应用声明的权限、系统授权步骤和运行时能力要求。
参考资料
- 华为开发者文档:HTTP数据请求
- 华为开发者文档:ArkUI状态管理与条件渲染
- 华为开发者文档:ArkTS API文档入口
说明:本文示例用于学习与讨论,尚未在实际 DevEco Studio、SDK、模拟器或真机上编译验证。请按项目实际版本核对 API,并补充真实运行结果。

更多推荐



所有评论(0)