在鸿蒙里优雅地处理网络错误:从 Demo 到实战案例
摘要
在做鸿蒙(HarmonyOS)应用开发时,网络请求基本是跑不掉的。无论是加载首页数据、拉取列表,还是提交表单,背后都依赖 HTTP 请求。可一旦遇到断网、超时、服务端 500 错误,应用就可能直接崩溃,用户体验会非常糟糕。
所以,如何优雅地处理网络错误,保证用户看到的不是“白屏”而是合理的提示,是开发过程中必须考虑的事情。
引言
随着鸿蒙生态越来越完善,应用也越来越复杂。以前我们可能只需要在局域网里访问接口,现在很多场景都涉及到公网请求,这也就意味着网络的不确定性大大增加。
比如:
- 用户在地铁里,信号忽强忽弱;
- 服务端升级中,短时间返回 503;
- 网络延迟过大,导致超时;
这些问题都会在真实应用里遇到,所以处理网络错误并不仅仅是“加一个 try-catch”,而是需要一个完整的容错方案。下面我会结合实际场景,展示具体的代码和解决办法。
鸿蒙里怎么捕获网络错误
最基本的做法就是在发起请求时对错误进行捕获和处理。鸿蒙提供了 @ohos.net.http
模块,可以很方便地发起请求并拿到结果。
基本 Demo
下面给一个最小可运行的示例:
import http from '@ohos.net.http';@Entry
@Component
struct NetworkErrorDemo {@State message: string = '点击按钮请求数据';doRequest() {let httpRequest = http.createHttp();httpRequest.request("https://example.com/api/data",{method: http.RequestMethod.GET,connectTimeout: 5000, // 超时时间readTimeout: 5000,},(err, data) => {if (err) {// 网络层异常,比如断网、超时this.message = `网络错误: ${err.message}`;return;}if (data.responseCode !== 200) {// 业务层异常,比如 404/500this.message = `请求失败: ${data.responseCode}`;} else {// 成功返回this.message = `成功: ${data.result}`;}});}build() {Column() {Text(this.message).fontSize(18).margin(10)Button("发起请求").onClick(() => this.doRequest()).margin(10)}}
}
这里的处理逻辑非常直接:
err
代表网络层的错误(比如超时、断网)。data.responseCode
可以拿到 HTTP 状态码(比如 404、500)。- 成功的情况再去解析
data.result
。
这样就能避免“用户点了按钮→没反应→程序崩了”的情况。
统一错误处理工具函数
实际项目里,我们不可能每个请求都写一堆 if (err) { ... }
。为了简化,可以写一个 统一的错误处理函数。
function handleHttpError(err?: Error, data?: http.HttpResponse): string {if (err) {return `网络异常: ${err.message}`;}if (!data) {return '未知错误';}if (data.responseCode >= 500) {return `服务器异常: ${data.responseCode}`;}if (data.responseCode >= 400) {return `请求错误: ${data.responseCode}`;}return '';
}
在业务代码里,就能这样写:
httpRequest.request("https://example.com/api/data", {}, (err, data) => {const errorMsg = handleHttpError(err, data);if (errorMsg) {this.message = errorMsg;return;}this.message = `成功: ${data?.result}`;
});
这样做的好处是,错误处理逻辑都收敛在一个地方,后期维护和扩展会方便很多。
实际场景案例
登录接口失败重试
用户点登录按钮时,如果网络瞬时断开,可以提示用户“重试”。
async function login(username: string, password: string): Promise<string> {return new Promise((resolve, reject) => {let httpRequest = http.createHttp();httpRequest.request("https://example.com/api/login",{method: http.RequestMethod.POST,extraData: { username, password }},(err, data) => {const errorMsg = handleHttpError(err, data);if (errorMsg) {reject(errorMsg);return;}resolve(data?.result ?? '');});});
}
在 UI 层就可以:
Button("登录").onClick(async () => {try {let result = await login("test", "123456");this.message = `登录成功: ${result}`;} catch (error) {this.message = `登录失败: ${error}`;}
});
列表加载失败时的兜底
当首页列表请求失败,可以展示一个“重试按钮”,而不是让用户看见空白。
if (this.message.startsWith("请求失败") || this.message.startsWith("网络错误")) {Button("重试").onClick(() => this.doRequest())
}
异常埋点上报
很多团队会在网络异常时,把错误日志上报到服务器,用于后续分析。比如:
function reportError(error: string) {console.log("上报错误:", error);// 实际中可以发送到日志服务
}
调用时:
const errorMsg = handleHttpError(err, data);
if (errorMsg) {reportError(errorMsg);this.message = errorMsg;return;
}
这样就能知道“哪些用户经常遇到 500”,“是不是某个版本里断网频繁”等问题。
常见问题 QA
Q1:网络请求要不要统一加超时?
建议加。因为如果不加超时,用户可能卡死在加载中,体验会非常差。
Q2:不同的接口要不要写不同的错误处理逻辑?
可以通用处理大部分错误(比如断网、500),但关键业务(比如支付、登录)最好再做特殊处理。
Q3:能不能全局捕获所有网络错误?
可以。思路是对 http.request
再封装一层,把错误统一在 Promise.catch
里处理。这样项目里的调用者就只需要关注业务逻辑。
总结
网络错误处理在鸿蒙应用开发里是绕不开的话题。一个健壮的应用,不能只考虑“正常返回”,还要考虑“异常兜底”。
通过:
- 基础的错误捕获;
- 统一的错误处理函数;
- 结合实际业务场景(登录、重试、埋点);
我们就能构建一个既稳定又易维护的网络层,保证应用在各种网络环境下都能“有话可说”,而不是让用户看到一个冷冰冰的白屏。