OpenHarmony http 网络请求封装与全局拦截实战(API Version23 + 适配版)

OpenHarmony http 网络请求封装与全局拦截实战(API Version23 + 适配版)
摘要http 模块是 OpenHarmony 原生网络请求能力用于后端接口交互、数据拉取提交涵盖 GET/POST/PUT/DELETE、文件上传下载、请求头统一配置、全局异常拦截、加载状态管理等场景。API Version23 重构网络底层线程调度、超时机制、证书校验、请求队列回收逻辑修复低版本并发请求堆积、超时无回调、跨域明文访问失效、大文件下载内存溢出、重复请求等兼容缺陷。旧项目升级 API23 后常出现接口请求无返回、请求超时卡死、https 证书报错、连续快速点击重复发起请求、返回 JSON 解析失败、页面销毁请求未取消造成内存泄漏等问题。本文基于 DevEco Studio API23 环境封装通用 http 请求工具类实现统一请求头、全局加载弹窗、错误码统一处理、重复请求防抖、页面销毁中断请求搭配资讯列表、登录提交、文件上传三大业务案例提供完整可运行代码输出网络权限、并发优化、资源释放规范汇总版本升级故障解决方案为鸿蒙前后端交互提供标准化请求模板。关键词OpenHarmonyArkUIAPI Version23http网络请求接口封装请求拦截全局 loading请求防抖一、引言1.1 网络请求开发背景几乎所有应用都依赖后端接口获取远程数据原生 http 模块支持标准 Restful 接口调用但原生 API 分散、缺少统一错误处理、无全局加载提示、未做重复请求拦截直接在页面零散调用会产生大量冗余代码、交互体验差。OpenHarmony API Version23 对 http 底层引擎大规模升级核心变更新增请求任务主动中断接口页面销毁可终止 pending 请求杜绝内存泄漏优化并发请求队列限制同时最大请求数量避免大量接口并发卡顿强化 https 证书校验规则废弃不安全明文 http 默认放行策略统一超时时间底层逻辑超时后强制返回失败回调不再无响应挂起修复大响应体 JSON 分段解析错乱、中文乱码问题区分主线程 / 子线程请求执行禁止 UI 线程执行超长阻塞请求。大量 API9~11 旧项目升级后退出页面接口依旧回调修改已销毁页面状态、http 明文地址无法访问、连续点击重复提交表单因此掌握 API23 标准化封装请求工具是前后端交互必备技能。1.2 前置配置与开发环境开发工具DevEco Studio 5.0 适配版本OpenHarmony API Version23 导入模块ohos.net.http 权限配置module.json5jsonrequestPermissions: [ { name: ohos.permission.INTERNET } ]测试场景GET 列表数据、POST 登录提交、表单传参、文件上传、全局加载弹窗、401 未登录拦截、页面销毁取消请求、重复点击防抖二、API23 http 核心 API 与版本变更说明2.1 核心创建与销毁http.createHttp ()创建独立请求实例一次请求一个实例httpRequest.destroy ()释放请求资源API23 必须主动调用否则连接残留httpRequest.on (complete)请求结束回调成功 / 失败都会执行用于销毁实例2.2 请求通用配置header请求头token、Content-Type、AcceptextraDataPOST/PUT 请求体数据readTimeout读取超时ms推荐 8000connectTimeout连接超时ms推荐 60002.3 支持请求方式HTTP.RequestMethod.GET / POST / PUT / DELETE2.4 API23 强制约束与废弃规则废弃全局单例 http 实例复用每次请求新建实例complete 中销毁明文 http 域名需要额外配置网络安全白名单否则请求失败页面离开必须调用 request.destroy () 终止请求防止回调已销毁组件单次请求响应体超大时自动分段读取禁止直接 JSON.parse 原始长字符串短时间高频重复请求必须加防抖锁API23 不自动拦截重复请求。三、通用全局 http 工具类封装utils/http_util.ets API23 标准etsimport http from ohos.net.http import promptAction from ohos.promptAction import AppStorage from ohos.arkui.state.AppStorage // 全局加载弹窗控制器 let loadingCount: number 0 let loadingCtrl: CustomDialogController | null null // 基础域名项目自行替换 const BASE_URL https://jsonplaceholder.typicode.com // 统一响应格式规范 interface ResponseDataT { code: number data: T msg: string } // 请求配置参数 interface RequestOption { url: string method: http.RequestMethod data?: Object showLoading?: boolean // 是否显示加载弹窗 } // 显示全局加载 function showLoading() { loadingCount if (loadingCount 1) { loadingCtrl new CustomDialogController({ builder: LoadingDialog(), autoCancel: false }) loadingCtrl.open() } } // 关闭全局加载 function hideLoading() { loadingCount-- if (loadingCount 0) { loadingCount 0 loadingCtrl?.close() loadingCtrl null } } class HttpUtil { // 基础请求封装 private async requestT(option: RequestOption): PromiseT | null { const { url, method, data, showLoading true } option // 显示加载弹窗 if (showLoading) showLoading() // 1. 创建独立请求实例 API23规范 const httpRequest http.createHttp() // 拼接完整地址 const fullUrl BASE_URL url // 统一请求头 const token AppStorage.Getstring(token) || const headers: Recordstring, string { Content-Type: application/json;charsetUTF-8 } if (token) headers[Authorization] Bearer ${token} try { // 发起请求 const res await httpRequest.request(fullUrl, { method: method, header: headers, extraData: data ? JSON.stringify(data) : , connectTimeout: 6000, readTimeout: 8000 }) // 请求完成销毁实例 httpRequest.destroy() hideLoading() // 状态码判断 if (res.responseCode ! 200) { promptAction.showToast({ message: 服务器错误${res.responseCode} }) return null } // 解析返回JSON const result: ResponseDataT JSON.parse(res.result as string) // 业务码拦截 401未登录跳转登录页 if (result.code 401) { AppStorage.Clear() router.clear() router.replaceUrl({ url: pages/login/login }) return null } if (result.code ! 200) { promptAction.showToast({ message: result.msg }) return null } return result.data } catch (err) { // 异常捕获超时、网络错误、解析失败 httpRequest.destroy() hideLoading() promptAction.showToast({ message: 网络请求失败请检查网络 }) console.error(http请求异常, err) return null } } // GET请求 async getT(url: string, showLoading: boolean true): PromiseT | null { return this.requestT({ url, method: http.RequestMethod.GET, showLoading }) } // POST提交表单/接口 async postT(url: string, data: Object, showLoading: boolean true): PromiseT | null { return this.requestT({ url, method: http.RequestMethod.POST, data, showLoading }) } } // 加载弹窗组件 CustomDialog struct LoadingDialog { build() { Column({ space: 15 }) { Text(加载中...).fontSize(16).fontColor(Color.White) } .width(120) .height(100) .backgroundColor(#00000099) .borderRadius(12) .justifyContent(FlexAlign.Center) } } export default new HttpUtil()四、四大业务实战场景API23 可直接运行4.1 实战一GET 拉取资讯列表页面etsimport HttpUtil from ../utils/http_util interface NewsItem { id: number title: string body: string } Entry Component struct NewsListPage { State newsList: NewsItem[] [] requestAbort: boolean false // 页面销毁标记中断回调渲染 async aboutToAppear() { this.requestAbort false await this.loadNewsData() } // 拉取列表接口 async loadNewsData() { const list await HttpUtil.getNewsItem[](/posts) // 页面已销毁不赋值UI防止报错 if (this.requestAbort || !list) return this.newsList list } build() { List({ space: 12 }) { ForEach(this.newsList, (item: NewsItem) { ListItem() { Column({ space: 6 }) { Text(item.title) .fontSize(17) .fontWeight(FontWeight.Medium) Text(item.body) .fontSize(14) .fontColor(#666) } .width(100%) .padding(15) .backgroundColor(Color.White) .borderRadius(10) } }) } .width(100%) .height(100%) .padding(15) .backgroundColor(#F5F5F5) } aboutToDisappear() { // API23关键页面销毁阻断接口回调更新状态避免内存泄漏 this.requestAbort true } }4.2 实战二POST 登录提交表单存储 token 全局etsimport HttpUtil from ../utils/http_util import router from ohos.router Entry Component struct LoginPage { State account: string State pwd: string // 登录提交 async handleLogin() { if (!this.account || !this.pwd) { promptAction.showToast({ message: 账号密码不能为空 }) return } const params { username: this.account, password: this.pwd } const res await HttpUtil.post{ token: string }(/login, params) if (!res) return // 存储token到全局与本地持久化 AppStorage.Set(token, res.token) AppStorage.Set(isLogin, true) await prefUtil.putString(token, res.token) // 替换页面跳转首页 router.replaceUrl({ url: pages/index/index }) } build() { Column({ space: 24 }) { Text(用户登录).fontSize(26).fontWeight(FontWeight.Bold) TextInput({ text: this.account, placeholder: 请输入账号 }) .width(100%).height(48) TextInput({ text: this.pwd, placeholder: 请输入密码 }) .type(InputType.Password) .width(100%).height(48) Button(登录) .width(100%).height(48) .backgroundColor(#007DFF) .onClick(async () await this.handleLogin()) } .padding(25) .width(100%) .height(100%) .justifyContent(FlexAlign.Center) } }4.3 实战三请求防抖防止按钮连续点击重复提交etsimport HttpUtil from ../utils/http_util Entry Component struct SubmitPage { lock: boolean false // 请求防抖锁 async submitForm() { // 防抖拦截正在请求直接返回 if (this.lock) return this.lock true const data { title: 测试提交内容 } const res await HttpUtil.post(/article/add, data) this.lock false if (res) promptAction.showToast({ message: 提交成功 }) } build() { Column() { Button(提交表单防抖保护) .width(240).height(48) .onClick(async () await this.submitForm()) } .width(100%) .height(100%) .justifyContent(FlexAlign.Center) } }4.4 实战四无加载弹窗静默请求下拉刷新列表etsimport HttpUtil from ../utils/http_util Entry Component struct RefreshNewsPage { State list: any[] [] async refreshData() { // 第二个参数false 不弹出全局loading const data await HttpUtil.get(/posts, false) if (data) this.list data } build() { List({ space: 10 }) { ForEach(this.list, item ListItem() { Text(item.title).padding(16) }) } .width(100%) .height(100%) .refresh({ refreshing: false }) .onRefresh(async () await this.refreshData()) } }五、API23 网络请求性能与内存优化规范5.1 请求实例管理规范每次请求新建http.createHttp()complete / 异常中必须执行destroy()释放连接禁止全局共用同一个 http 实例并发请求会造成参数错乱。5.2 页面内存泄漏防护API23 重点页面定义requestAbort标记aboutToDisappear置为 true接口回调赋值 UI 前先判断标记页面销毁不再修改 State短页面频繁进出场景减少并发请求优先缓存数据。5.3 交互体验优化规范新增防抖锁 lock按钮提交、分页加载防止重复请求长耗时接口开启全局 Loading 弹窗快速刷新列表关闭 Loading统一捕获所有异常使用 toast 提示用户避免空白无反馈。5.4 安全与权限规范接口 token 统一放在请求头 Authorization封装在工具类无需页面重复处理业务码 401 自动清空登录态跳转登录页全局统一拦截明文 http 域名需要在工程网络配置添加白名单API23 默认拦截 http。六、API23 升级高频兼容问题与解决方案问题 1退出页面后接口返回程序闪退 / 控制台报错 解决页面增加销毁标记回调赋值 UI 前判断标记页面销毁终止状态更新。问题 2http 明文接口请求失败无返回 解决module.json5 配置网络安全白名单仅测试环境使用 http线上强制 https。问题 3快速多次点击按钮重复提交多条数据 解决添加布尔防抖锁请求中拦截重复点击。问题 4接口返回中文乱码、JSON 解析报错 解决请求头强制设置charsetUTF-8统一使用 JSON 序列化传参。问题 5请求超时无任何提示页面卡死 解决配置 connectTimeout、readTimeout工具类统一捕获异常弹出 toast。问题 6多次请求后网络连接堆积应用卡顿 解决每次请求结束调用httpRequest.destroy()释放资源。七、总结http 网络请求是应用远程数据交互核心模块API Version23 重构请求实例生命周期、超时调度、资源释放逻辑强制每次请求独立创建并销毁实例解决低版本连接残留、回调泄漏、并发错乱等问题。项目统一封装全局请求工具类内置 loading 加载、token 自动携带、401 登录拦截、异常统一提示、防抖防重复提交大幅减少页面重复代码。