前面的例子用的都是本地模拟数据。本文讲数据从服务器拉取。鸿蒙的网络请求用 @kit.NetworkKit
里的 http
模块,异步处理用 async/await
。学完这篇,列表数据、详情数据换成真实接口。
16.1 http 模块基础:发送 GET 请求
模块导入 @kit.NetworkKit
import { http } from '@kit.NetworkKit';
最基础的 GET 请求:
import { http } from '@kit.NetworkKit';
const httpRequest = http.createHttp();
const requestOptions: http.HttpRequestOptions = {
method: http.RequestMethod.GET,
header: { 'Content-Type': 'application/json' },
connectTimeout: 15000,
readTimeout: 15000
};
httpRequest.request(
'https://api.example.com/articles',
requestOptions,
(err, data) => {
if (!err) {
console.log('请求成功:' + data.result);
} else {
console.error('请求失败:' + err.message);
}
}
);
createHttp()
创建一个 HTTP 客户端实例。request()
发请求,第一个参数是 URL,第二个是 HttpRequestOptions
配置对象,第三个是回调。
connectTimeout
是建立连接的超时时间,readTimeout
是等待服务器响应的超时时间,单位毫秒。设了超时就不用担心请求卡死。
请求完成销毁实例,释放资源:
httpRequest.destroy();
16.2 请求参数和返回数据,全部对象化
这是本文的重点,所有参数和返回数据都必须用对象。
请求参数:
要带查询参数,不要自己在 URL 后面拼 ?key=value&key2=value2
。用 extraData
传一个对象,框架自动序列化:
const requestOptions: http.HttpRequestOptions = {
method: http.RequestMethod.GET,
extraData: {
page: 1,
pageSize: 20,
category: 'tech'
},
connectTimeout: 15000,
readTimeout: 15000
};
旧写法里 data.result
返回的是 string,每次都要手动 JSON.parse
。expectDataType
设为 http.HttpDataType.OBJECT
,data.result
是解析好的对象。
const requestOptions: http.HttpRequestOptions = {
method: http.RequestMethod.GET,
expectDataType: http.HttpDataType.OBJECT,
connectTimeout: 15000,
readTimeout: 15000
};
const response = await httpRequest.request('https://api.example.com/articles', requestOptions);
// 不需要 JSON.parse,直接用
const result = response.result as ApiResponse;
if (result.code === 200) {
this.articleList = result.data;
}
expectDataType
支持三种:
STRING- :返回字符串(默认,旧行为)
OBJECT- :返回解析好的对象,省掉 JSON.parse
ARRAY_BUFFER- :返回二进制数据,图片、文件下载用
16.3 用 async/await 改写
用 async/await
,异步代码读起来跟同步一样:
import { http } from '@kit.NetworkKit';
async function fetchArticles(): Promise<Article[]> {
const httpRequest = http.createHttp();
try {
const requestOptions: http.HttpRequestOptions = {
method: http.RequestMethod.GET,
expectDataType: http.HttpDataType.OBJECT,
connectTimeout: 15000,
readTimeout: 15000
};
const response = await httpRequest.request('https://api.example.com/articles', requestOptions);
const result = response.result as ApiResponse;
return result.code === 200 ? result.data : [];
} catch (err) {
console.error('请求失败:' + JSON.stringify(err));
return [];
} finally {
httpRequest.destroy();
}
}
await
等待请求结果,try-catch
捕获异常,finally
里销毁实例。
await
只能放在 async
函数里。build()
方法不是 async 函数,网络请求的逻辑要封装成 async 函数,在 aboutToAppear
或其他生命周期里调用。
16.4 定义数据模型
接口返回什么结构,就用 type
或 interface
定义清楚。这是对象化的前提——数据进来到出去,每一步都有类型约束:
// 文章对象
type Article = {
id: string;
title: string;
author: string;
readCount: number;
};
// 接口返回体
type ApiResponse = {
code: number;
data: Article[];
message?: string;
};
16.5 数据驱动 UI 刷新
解析完的数据赋值给 @State 变量,UI 自动刷新:
import { http } from '@kit.NetworkKit';
@Entry
@Component
struct ArticleListPage {
@State articleList: Article[] = [];
@State isLoading: boolean = false;
async aboutToAppear(): Promise<void> {
await this.loadArticles();
}
async loadArticles(): Promise<void> {
this.isLoading = true;
const httpRequest = http.createHttp();
try {
const requestOptions: http.HttpRequestOptions = {
method: http.RequestMethod.GET,
expectDataType: http.HttpDataType.OBJECT,
extraData: { page: 1, pageSize: 20 },
connectTimeout: 15000,
readTimeout: 15000
};
const response = await httpRequest.request('https://api.example.com/articles', requestOptions);
const result = response.result as ApiResponse;
if (result.code === 200) {
this.articleList = result.data; // 赋值,UI 自动刷新
}
} catch (err) {
console.error('加载失败:' + JSON.stringify(err));
} finally {
this.isLoading = false;
httpRequest.destroy();
}
}
build() {
if (this.isLoading) {
Column() {
Text('加载中...')
.fontSize(16)
.fontColor('#999999')
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
List() {
ForEach(this.articleList, (item: Article) => {
ListItem() {
Column() {
Text(item.title)
.fontSize(18)
.fontWeight(FontWeight.Medium)
Row() {
Text(item.author)
.fontSize(14)
.fontColor('#666666')
Text(`${item.readCount}阅读`)
.fontSize(14)
.fontColor('#999999')
.margin({ left: 10 })
}
.margin({ top: 8 })
}
.padding(16)
.width('100%')
}
})
}
}
}
注意:需要网络请求必须在 module.json5
里声明权限:
"requestPermissions": [
{ "name": "ohos.permission.INTERNET" }
]
16.6 常见报错处理
请求没反应也没报错:检查 module.json5
里有没有声明 INTERNET 权限。没声明权限,请求会失败。
导入报错:检查导入路径是不是 import { http } from '@kit.NetworkKit'
。旧的 @ohos.net.http
已经废弃。
await
编译报错:await
只能放在 async
函数里。build()
方法不是 async 函数。
JSON.parse
报错:如果用 expectDataType: http.HttpDataType.OBJECT
,不用手动 JSON.parse
16.7 本篇总结
- http 模块:
import { http } from '@kit.NetworkKit' - ,
createHttp() - 创建实例,
request() - 发请求,
destroy() - 释放。
- 请求配置对象化:所有请求参数通过
HttpRequestOptions - 对象传递,含
method - 、
extraData - 、
expectDataType - 、
connectTimeout - 、
readTimeout - 。
- 参数对象化:
extraData - 传对象,不拼 URL。
- 返回数据对象化:
expectDataType: http.HttpDataType.OBJECT - ,直接拿对象,省掉
JSON.parse - 。
- async/await:异步代码同步写法,
try-catch-finally - 处理异常和清理。
- 数据驱动 UI:@State 变量赋值后 UI 自动刷新。
常见问题
Q: 新版 http 怎么导入?
A: import { http } from '@kit.NetworkKit'
。旧的 @ohos.net.http
已废弃。
Q: 请求参数怎么传?
A: GET 参数和 POST 请求体都用 extraData
传对象,框架自动序列化。
Q: 返回数据怎么直接拿对象?
A: 设置 expectDataType: http.HttpDataType.OBJECT
,result
直接是对象,不用 JSON.parse
Q: 超时怎么设?
A: HttpRequestOptions
里设 connectTimeout
(连接超时)和 readTimeout
(读取超时),单位毫秒。
Q: 发网络请求需要什么权限?
A: module.json5
里声明 ohos.permission.INTERNET
重庆华鸿科技 深耕鸿蒙生态人才培养,推出《HarmonyOS 应用开发者认证培训班》《HarmonyOS 应用开发者原生开发精研班》《HarmonyOS 原生应用项目实战与就业班》,由华为官方认证讲师授课,手把手带您从零构建商业级鸿蒙应用。