一、前言
应用开发离不开网络交互,从首页商品、资讯加载到登录提交,都需要调用后端接口。OpenHarmony 原生使用fetch实现 http/https 网络请求,无需额外引入三方库,支持 GET、POST、请求头配置、JSON 解析。本文讲解基础请求、参数传递、异常捕获,搭配真实模拟接口,结合前面 Preferences、ArkUI 组件完成网络数据列表展示实战。
开发前置:配置网络权限 项目目录
src/main/module.json5→ module.requestPermissions 添加网络权限:
json
"requestPermissions": [ { "name": "ohos.permission.INTERNET" } ]二、Fetch 基础语法说明
fetch 返回 Promise 异步对象,分为两步:
- fetch (url, options) 发起请求,返回 Response 响应对象
- response.json () 解析 json 格式数据
- GET:参数拼在 URL 末尾
- POST:参数放在 body 中,需配置请求头
Content-Type
三、GET 请求实战(无参 / 带参)
3.1 无参数 GET 获取接口数据
ets
@Entry @Component struct FetchGetDemo { @State resText: string = "" // GET请求 async requestGet() { try { // 公开测试JSON接口 let resp = await fetch("https://jsonplaceholder.typicode.com/posts/1") let data = await resp.json() this.resText = JSON.stringify(data, null, 2) } catch (err) { this.resText = "请求异常:" + JSON.stringify(err) } } build() { Column({ space: 15 }) { Button("发起GET请求").onClick(() => this.requestGet()) Scroll() { Text(this.resText).fontSize(14).padding(10) } .width("100%") .layoutWeight(1) } .padding(20) .height("100%") } }3.2 GET 拼接请求参数
ets
async getWithParam() { let id = 5 let url = `https://jsonplaceholder.typicode.com/posts/${id}` let res = await fetch(url) let result = await res.json() console.info("携带参数数据:", result.title) }四、POST 请求(提交表单 JSON 参数)
POST 多用于登录、提交表单,请求体使用 JSON 格式,固定请求头:Content-Type: application/json
ets
async requestPost() { let url = "https://jsonplaceholder.typicode.com/posts" // 请求参数 let bodyData = { title: "OpenHarmony测试文章", body: "鸿蒙fetch网络开发", userId: 1 } let options: RequestInit = { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(bodyData) } try { let resp = await fetch(url, options) let data = await resp.json() console.info("POST返回数据:", data) } catch (e) { console.error("请求失败", e) } }五、封装通用网络请求工具类
项目中统一封装请求,统一处理异常、请求头,便于后期维护:
ets
class HttpUtil { // 通用GET static async get(url: string) { let res = await fetch(url) if (!res.ok) throw new Error("接口异常:" + res.status) return await res.json() } // 通用POST static async post(url: string, data: Object) { let opt: RequestInit = { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data) } let res = await fetch(url, opt) if (!res.ok) throw new Error("接口异常:" + res.status) return await res.json() } }六、综合实战:网络数据渲染 List 列表(融合懒加载 LazyForEach)
业务:请求接口批量获取文章数据,通过 LazyForEach 渲染列表,下拉刷新重新请求接口。
ets
// 懒加载数据源 class ArticleDataSource implements ICollectionData { private list: Array<Object> = [] setData(arr: Object[]) { this.list = arr } getTotalCount(): number { return this.list.length } getData(index: number): Object { return this.list[index] } setDataChangeListener(listener: DataChangeListener): void {} } @Entry @Component struct NetListPage { @State isRefresh: boolean = false dataSource: ArticleDataSource = new ArticleDataSource() // 请求接口刷新数据 async loadArticle() { this.isRefresh = true try { let list = await HttpUtil.get("https://jsonplaceholder.typicode.com/posts?_limit=20") this.dataSource.setData(list) } catch (err) { console.error("数据加载失败", err) } finally { this.isRefresh = false } } aboutToAppear() { this.loadArticle() } build() { Column() { Text("资讯列表").fontSize(22).fontWeight(Font.Bold).padding(15) List() { LazyForEach(this.dataSource, (item: any) => { ListItem() { Column({ space:6 }) { Text(item.title).fontSize(16).fontWeight(FontWeight.Bold) Text(item.body).fontSize(14).fontColor("#666") } .width("100%") .padding(12) .backgroundColor("#fff") .borderRadius(8) .margin({ bottom:8 }) } }) } .width("100%") .layoutWeight(1) .refresh({refreshing: this.isRefresh}) .onRefresh(()=>this.loadArticle()) } .width("100%") .backgroundColor("#F5F5F5") } }七、拓展实战:登录页网络提交 + 本地存储(融合 Preferences)
点击登录发起 POST 请求,登录成功后使用 Preferences 保存登录状态。
ets
import preferences from '@ohos.data.preferences' import common from '@ohos.app.ability.common' @Entry @Component struct NetLoginPage { @State account: string = "" @State pwd: string = "" context = getContext(this) as common.UIAbilityContext // 登录请求 async doLogin() { let loginParam = { username: this.account, password: this.pwd } try { // 模拟登录接口 let res = await HttpUtil.post("https://jsonplaceholder.typicode.com/users", loginParam) // 登录成功,持久化保存登录标识 let pre = await preferences.getPreferences(this.context, "user_login") await pre.put("isLogin", true) await pre.put("userName", this.account) await pre.flush() AlertDialog.show({title:"提示",message:"登录成功!"}) } catch (err) { AlertDialog.show({title:"提示",message:"登录失败"}) } } build() { Column({ space:20 }) { TextInput({placeholder:"账号"}).width("90%").onChange(v=>this.account=v) TextInput({placeholder:"密码"}).type(InputType.Password).width("90%").onChange(v=>this.pwd=v) Button("登录").width("90%").backgroundColor("#007DFF").onClick(()=>this.doLogin()) } .width("100%").height("100%").justifyContent(FlexAlign.Center).padding(20) } }八、开发规范与踩坑总结
- 权限必开:忘记配置 INTERNET 会直接请求报错;
- 异常捕获:所有网络请求必须套
try/catch,避免断网闪退; - 数据格式:POST 传 JSON 必须配置 Header,否则后端无法解析参数;
- 频繁请求优化:页面销毁时取消无用请求,避免内存浪费;
- HTTPS 优先:OpenHarmony 默认支持 https,http 部分设备需要额外配置白名单。