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