鸿蒙 APP 开发实战:网络请求与数据持久化
鸿蒙 APP 开发中的网络请求与数据持久化技术。内容包括鸿蒙官方 HTTP 请求库的配置与封装,实现了 GET/POST 请求、拦截器及错误处理机制。通过商品服务和用户服务的代码示例,展示了如何调用 API 并处理响应数据。此外,文章还涵盖了网络状态检测的实现,以及利用 Preferences 进行轻量级键值对存储和利用 SQLite 进行结构化数据持久化的具体实践。最后提供了加载动画与错误界面的组件实现,帮助开发者提升应用的用户体验。

鸿蒙 APP 开发中的网络请求与数据持久化技术。内容包括鸿蒙官方 HTTP 请求库的配置与封装,实现了 GET/POST 请求、拦截器及错误处理机制。通过商品服务和用户服务的代码示例,展示了如何调用 API 并处理响应数据。此外,文章还涵盖了网络状态检测的实现,以及利用 Preferences 进行轻量级键值对存储和利用 SQLite 进行结构化数据持久化的具体实践。最后提供了加载动画与错误界面的组件实现,帮助开发者提升应用的用户体验。


本文介绍鸿蒙应用开发中的网络通信与本地数据存储技术,涵盖官方 HTTP 请求库的使用、Preferences 轻量级存储及 SQLite 关系型数据库的集成方案。
主要内容:
HarmonyOS Next 提供官方 HTTP 请求库,支持 HTTP/HTTPS 协议,功能包括发送 GET/POST/PUT/DELETE 请求、设置请求头与参数、文件上传下载、拦截器配置以及超时重试机制。
在 entry/src/main/module.json5 中添加网络权限:
{
"module": {
"requestPermissions": [
{"name": "ohos.permission.INTERNET"},
{"name": "ohos.permission.READ_NETWORK_STATE"},
{"name": "ohos.permission.WRITE_NETWORK_STATE"}
]
}
}
创建 entry/src/main/ets/utils/HttpUtils.ets:
import http from '@ohos.net.http';
// 网络请求配置
const HTTP_CONFIG = {
baseUrl: 'https://api.example.com', // 替换为你的 API 地址
timeout: 10000, // 超时时间(毫秒)
retryCount: 3 // 重试次数
};
// 网络请求工具类
export class HttpUtils {
private static instance: HttpUtils | null = null;
private httpRequest: http.HttpRequest | null = null;
// 单例模式
static getInstance(): HttpUtils {
if (!HttpUtils.instance) {
HttpUtils.instance = new HttpUtils();
}
return HttpUtils.instance;
}
// 初始化 HTTP 请求
private initRequest(): void {
if (!this.httpRequest) {
this.httpRequest = http.createHttp();
}
}
// 发送 GET 请求
async get<T>(url: string, params?: Record<string, any>): Promise<T> {
this.initRequest();
const fullUrl = this.buildUrl(url, params);
const response = await this.httpRequest!.request(fullUrl, {
method: http.RequestMethod.GET,
header: { 'Content-Type': 'application/json' },
connectTimeout: HTTP_CONFIG.timeout,
readTimeout: HTTP_CONFIG.timeout
});
return this.handleResponse<T>(response);
}
// 发送 POST 请求
async post<T>(url: string, data?: Record<string, any>): Promise<T> {
this.initRequest();
const fullUrl = this.buildUrl(url);
const response = await this.httpRequest!.request(fullUrl, {
method: http.RequestMethod.POST,
header: { 'Content-Type': 'application/json' },
extraData: data,
connectTimeout: HTTP_CONFIG.timeout,
readTimeout: HTTP_CONFIG.timeout
});
return this.handleResponse<T>(response);
}
// 构建完整 URL
private buildUrl(url: string, params?: Record<string, any>): string {
let fullUrl = `${HTTP_CONFIG.baseUrl}${url}`;
if (params) {
const queryString = Object.keys(params).map(key => `${key}=${encodeURIComponent(params[key])}`).join('&');
fullUrl += `?${queryString}`;
}
return fullUrl;
}
// 处理响应
private async handleResponse<T>(response: http.HttpResponse): Promise<T> {
if (response.responseCode === 200) {
const result = JSON.parse(response.result.toString());
if (result.code === 200) {
return result.data;
} else {
throw new Error(result.message || '请求失败');
}
} else {
throw new Error(`HTTP 错误:${response.responseCode}`);
}
}
}
创建 entry/src/main/ets/services/ProductService.ets:
import { HttpUtils } from '../utils/HttpUtils';
import { GoodsModel } from '../models/HomeModel';
// 商品 API 响应数据模型
export interface ProductResponseModel {
code: number;
message: string;
data: Array<GoodsModel>;
}
// 商品服务
export class ProductService {
private static instance: ProductService | null = null;
static getInstance(): ProductService {
if (!ProductService.instance) {
ProductService.instance = new ProductService();
}
return ProductService.instance;
}
// 获取商品列表
async getProductList(): Promise<Array<GoodsModel>> {
const response = await HttpUtils.getInstance().get<Array<>>();
response;
}
(: ): <> {
response = .().<>();
response;
}
}
创建 entry/src/main/ets/services/UserService.ets:
import { HttpUtils } from '../utils/HttpUtils';
// 用户登录请求数据模型
export interface LoginRequestModel {
username: string;
password: string;
}
// 用户登录响应数据模型
export interface LoginResponseModel {
code: number;
message: string;
data: { token: string; userInfo: UserInfoModel; };
}
// 用户信息数据模型
export interface UserInfoModel {
id: number;
username: string;
avatar: string;
nickname: string;
email: string;
phone: string;
gender: number;
birthday: string;
}
// 用户服务
export class UserService {
private static instance: UserService | null = null;
(): {
(!.) {
. = ();
}
.;
}
(: ): <[]> {
response = .().<[]>(, request);
response;
}
(: ): <[]> {
response = .().<[]>(, request);
response;
}
(): <> {
response = .().<>();
response;
}
}
创建 entry/src/main/ets/services/NetworkService.ets:
import network from '@ohos.net.network';
// 网络状态类型
export type NetworkType = 'wifi' | 'cellular' | 'none';
// 网络状态服务
export class NetworkService {
private static instance: NetworkService | null = null;
static getInstance(): NetworkService {
if (!NetworkService.instance) {
NetworkService.instance = new NetworkService();
}
return NetworkService.instance;
}
// 获取当前网络状态
getCurrentNetworkType(): NetworkType {
const networkType = network.getNetworkTypeSync();
switch (networkType) {
case network.NetworkType.WIFI:
return 'wifi';
case network.NetworkType.CELLULAR:
return 'cellular';
default:
return 'none';
}
}
(: ): {
network.(, {
(.());
});
network.(, {
();
});
}
}
创建 entry/src/main/ets/components/NetworkStatusComponent.ets:
import { NetworkService } from '../services/NetworkService';
@Component
export struct NetworkStatusComponent {
@State networkType: NetworkService.NetworkType = 'wifi';
build() {
Row({ space: 8 }) {
Image(this.networkType === 'wifi' ? $r('app.media.wifi') : this.networkType === 'cellular' ? $r('app.media.cellular') : $r('app.media.none'))
.width(20)
.height(20)
.objectFit(ImageFit.Contain);
Text(this.networkType === 'wifi' ? 'WiFi' : this.networkType === 'cellular' ? '移动网络' : '无网络')
.fontSize(14)
.textColor(this.networkType === 'none' ? '#FF0000' : '#666666');
}
.width('auto')
.()
.(, , , )
.(. === ? : )
.()
.(. === );
}
() {
. = .().();
.().( {
. = ;
});
}
}
HarmonyOS Next 提供三种主要数据持久化方式:
| 方式 | 功能 | 适用场景 |
|---|---|---|
| Preferences | 轻量级存储,支持键值对存储 | 用户设置、应用配置、购物车数据等小体积数据 |
| SQLite | 关系型数据库,支持复杂查询 | 商品列表、用户信息、订单数据等结构化数据 |
| Distributed Data | 分布式存储,支持跨设备数据同步 | 超级终端多设备协同场景 |
创建 entry/src/main/ets/utils/PreferencesUtils.ets:
import preferences from '@ohos.data.preferences';
import { UIAbilityContext } from '@ohos.abilityAccessCtrl';
// Preferences 工具类
export class PreferencesUtils {
private static instance: PreferencesUtils | null = null;
private dataPreferences: preferences.Preferences | null = null;
static getInstance(): PreferencesUtils {
if (!PreferencesUtils.instance) {
PreferencesUtils.instance = new PreferencesUtils();
}
return PreferencesUtils.instance;
}
// 初始化 Preferences
async init(context: UIAbilityContext): Promise<void> {
if (!this.dataPreferences) {
this.dataPreferences = await preferences.getPreferences(context, 'app_preferences');
}
}
// 获取值
get<T>(key: , : T): T {
(!.) {
defaultValue;
}
..(key, defaultValue) T;
}
put<T>(: , : T): <> {
(!.) {
;
}
..(key, value);
..();
}
(: ): <> {
(!.) {
;
}
..(key);
..();
}
(): <> {
(!.) {
;
}
keys = ..();
( key keys) {
..(key);
}
..();
}
}
修改 entry/src/main/ets/services/UserService.ets:
import { HttpUtils } from '../utils/HttpUtils';
import { PreferencesUtils } from '../utils/PreferencesUtils';
// 用户服务
export class UserService {
// ... 其他方法
// 用户登录(添加 token 存储)
async login(request: LoginRequestModel): Promise<LoginResponseModel['data']> {
const response = await HttpUtils.getInstance().post<LoginResponseModel['data']>('/api/login', request);
// 存储 token 到 Preferences
await PreferencesUtils.getInstance().put('token', response.token);
return response;
}
// 获取用户信息(添加 token 认证)
async getUserInfo(): Promise<UserInfoModel> {
const token = PreferencesUtils.getInstance().get<string>('token', '');
HttpUtils.getInstance().addHeader('Authorization', );
response = .().<>();
response;
}
}
创建 entry/src/main/ets/utils/SQLiteUtils.ets:
import relationalStore from '@ohos.data.relationalStore';
import { UIAbilityContext } from '@ohos.abilityAccessCtrl';
// 数据库配置
const DB_CONFIG = {
name: 'app_db.db',
securityLevel: relationalStore.SecurityLevel.S1
};
// SQLite 数据库管理类
export class SQLiteUtils {
private static instance: SQLiteUtils | null = null;
private rdbStore: relationalStore.RdbStore | null = null;
static getInstance(): SQLiteUtils {
if (!SQLiteUtils.instance) {
SQLiteUtils.instance = new SQLiteUtils();
}
return SQLiteUtils.instance;
}
// 初始化数据库
async init(context: UIAbilityContext): Promise<void> {
if (!this.rdbStore) {
. = relationalStore.(context, );
.();
.();
.();
}
}
(): <> {
sql = ;
.!.(sql);
}
(): <> {
sql = ;
.!.(sql);
}
(): <> {
sql = ;
.!.(sql);
}
(: , ?: <>): <<relationalStore.>> {
(!.) {
[];
}
resultSet = ..(sql, args);
: <relationalStore.> = [];
(resultSet.()) {
{
data.(resultSet);
} (resultSet.());
}
data;
}
(: , : <, >): <> {
(!.) {
-;
}
rowId = ..(tableName, values);
rowId;
}
(: , : <, >, ?: , ?: <>): <> {
(!.) {
;
}
count = ..(tableName, values, whereClause, whereArgs);
count;
}
(: , ?: , ?: <>): <> {
(!.) {
;
}
count = ..(tableName, whereClause, whereArgs);
count;
}
}
修改 entry/src/main/ets/services/ProductService.ets:
import { HttpUtils } from '../utils/HttpUtils';
import { GoodsModel } from '../models/HomeModel';
import { SQLiteUtils } from '../utils/SQLiteUtils';
// 商品服务
export class ProductService {
// ... 其他方法
// 获取商品列表(先从本地数据库获取,再从网络获取)
async getProductList(): Promise<Array<GoodsModel>> {
// 先从本地数据库获取
const localData = await this.getProductListFromLocal();
if (localData.length > 0) {
return localData;
}
// 本地数据库无数据,从网络获取
const remoteData = await this.getProductListFromRemote();
// 将网络数据存入本地数据库
await this.saveProductListToLocal(remoteData);
return remoteData;
}
// 从本地数据库获取商品列表
private async getProductListFromLocal(): Promise<Array<GoodsModel>> {
const sql = 'SELECT * FROM product';
resultSet = .().(sql);
: <> = [];
resultSet.( {
data.({
: row.(row.()),
: row.(row.()),
: row.(row.()),
: row.(row.()),
: row.(row.()),
: row.(row.())
});
});
data;
}
(): <<>> {
response = .().<<>>();
response;
}
(: <>): <> {
( item data) {
.().(, {
: item.,
: item.,
: item.,
: item.,
: item.,
: item.
});
}
}
}
创建 entry/src/main/ets/components/LoadingComponent.ets:
@Component
export struct LoadingComponent {
@Prop isLoading: boolean = false;
build() {
Column({ space: 16 }) {
Progress({ value: 0, total: 100, type: ProgressType.ScaleRing })
.width(60)
.height(60)
.style({ strokeWidth: 5, scaleCount: 12, duration: 1000 });
Text('加载中...').fontSize(14).textColor('#666666');
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
.visible(this.isLoading);
}
}
创建 entry/src/main/ets/components/ErrorComponent.ets:
@Component
export struct ErrorComponent {
@Prop isError: boolean = false;
@Prop errorMessage: string = '请求失败';
onRetry: () => void;
build() {
Column({ space: 16 }) {
Image($r('app.media.error')).width(80).height(80).objectFit(ImageFit.Contain);
Text(this.errorMessage).fontSize(14).textColor('#666666');
Button('重试').width(120).height(48).backgroundColor('#007DFF').onClick(() => this.onRetry());
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
.visible(this.);
}
}
在 entry/src/main/ets/utils/HttpUtils.ets 中替换为你的真实 API 地址:
const HTTP_CONFIG = {
baseUrl: 'https://your-api-address.com', // 替换为你的 API 地址
// ...
};
在 entry/src/main/ets/entryability/EntryAbility.ts 中初始化 Preferences 和 SQLite:
import { PreferencesUtils } from '../utils/PreferencesUtils';
import { SQLiteUtils } from '../utils/SQLiteUtils';
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
// 初始化 Preferences
PreferencesUtils.getInstance().init(this.context);
// 初始化 SQLite
SQLiteUtils.getInstance().init(this.context);
}
// ...
}
效果验证:

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online
将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online