OpenHarmony 网络请求 axios 封装(@ohos.net.http API23 适配)
摘要原生ohos.net.http底层 API 写法繁琐缺少统一拦截、超时、错误统一处理、loading 全局控制、请求取消、token 自动携带等通用能力。基于原生 http 封装类 axios 风格网络工具统一管理全局请求头、请求拦截、响应拦截、异常捕获、加载弹窗适配 GET/POST/PUT/DELETE 文件上传表单提交。API23 重构 http 请求生命周期、连接复用、请求销毁机制修复并发请求堆积、页面销毁未中断请求造成内存泄漏、网络切换请求失败、大文件上传卡顿等问题。本文提供完整可直接复用的 http 工具类搭配登录、资讯列表、文件上传业务页面实战统一规范前后端交互格式汇总网络常见报错解决方案是所有鸿蒙项目必备底层工具。关键词OpenHarmonyAPI23http 网络请求请求拦截响应拦截文件上传全局 loading请求取消一、引言1.1 网络封装开发背景几乎所有应用都需要和后端服务交互原生 http 存在大量重复模板代码每次请求手动添加 token、Content-Type 请求头重复写加载弹窗、失败 toast 提示页面退出时未终止进行中的请求造成回调触发已销毁页面报错无统一错误码处理401 未登录、500 服务异常、超时文件上传表单参数拼接逻辑复杂。统一封装网络工具实现请求拦截统一注入 token、响应拦截统一解析返回数据、全局 loading 自动显示隐藏、页面销毁批量取消请求、统一异常分发大幅减少页面冗余代码。API23 http 模块核心更新HttpRequest 实例支持 abort () 主动中断请求防止页面销毁回调泄漏优化长连接复用并发请求性能提升新增超时强拦截超时直接触发失败回调不会无限阻塞修复 https 证书校验失败闪退问题支持配置忽略证书调试表单上传文件流接口标准化废弃旧版 Blob 兼容写法。1.2 前置权限配置module.json5 添加网络权限jsonrequestPermissions: [ { name: ohos.permission.INTERNET } ]开发调试如需访问 http 明文接口在 module.json5 增加网络安全配置jsonnetwork: { cleartextTraffic: true }二、原生 http 基础 API 示例etsimport http from ohos.net.http // 创建请求实例 let httpReq http.createHttp() // GET请求 httpReq.request( https://xxx/api/list, { method: http.RequestMethod.GET, header: { Content-Type: application/json }, readTimeout: 10000, connectTimeout: 10000 }, (err, res) { httpReq.destroy() // 释放实例 if (!err) { console.info(数据, res.result) } } ) // 中断请求 httpReq.abort()三、完整网络工具封装 utils/http_util.etsetsimport http from ohos.net.http import promptAction from ohos.promptAction import AppStorage from ohos.arkui.state.AppStorage import { STORAGE_KEY } from ../model/Constant // 基础域名 const BASE_URL https://jsonplaceholder.typicode.com // 存储页面请求集合页面销毁批量取消 const requestPool: Sethttp.HttpRequest new Set() // 统一响应数据格式 export interface ResponseDataT { code: number data: T msg: string } // 请求配置 interface RequestOptions { url: string method: http.RequestMethod data?: Object | string showLoading?: boolean timeout?: number } class HttpUtil { private static instance: HttpUtil static getInstance() { if (!HttpUtil.instance) { HttpUtil.instance new HttpUtil() } return HttpUtil.instance } // 清除全部进行中的请求页面销毁调用 clearAllRequest() { requestPool.forEach(req { req.abort() req.destroy() }) requestPool.clear() } // 核心请求方法 async requestT(options: RequestOptions): PromiseResponseDataT | null { const { url, method, data, showLoading true, timeout 10000 } options const fullUrl BASE_URL url // 全局token const token AppStorage.Getstring(STORAGE_KEY.TOKEN) // 请求头 const header: Recordstring, string { Content-Type: application/json } if (token) header.Authorization Bearer ${token} let httpReq http.createHttp() requestPool.add(httpReq) // 加载弹窗 if (showLoading) promptAction.showLoading() try { const params: http.HttpRequestOptions { method, header, readTimeout: timeout, connectTimeout: timeout } // POST传参 if (data (method http.RequestMethod.POST || method http.RequestMethod.PUT)) { params.extraData JSON.stringify(data) } const res await httpReq.request(fullUrl, params) // 释放请求实例 httpReq.destroy() requestPool.delete(httpReq) if (showLoading) promptAction.closeLoading() // 状态码判断 if (res.responseCode ! 200) { promptAction.showToast({ message: 请求错误${res.responseCode} }) return null } const result: ResponseDataT JSON.parse(res.result as string) // 业务错误码统一处理 if (result.code ! 200) { // 401 未登录清空登录状态跳转登录页 if (result.code 401) { AppStorage.Set(STORAGE_KEY.IS_LOGIN, false) promptAction.showToast({ message: 登录失效请重新登录 }) } else { promptAction.showToast({ message: result.msg || 接口异常 }) } return null } return result } catch (err) { httpReq.destroy() requestPool.delete(httpReq) if (showLoading) promptAction.closeLoading() // 判断是否主动中断 if ((err as Error).message.includes(abort)) { return null } promptAction.showToast({ message: 网络请求失败请检查网络 }) console.error(http请求异常, err) return null } } // GET封装 getT(url: string, showLoading true) { return this.requestT({ url, method: http.RequestMethod.GET, showLoading }) } // POST封装 postT(url: string, data?: Object, showLoading true) { return this.requestT({ url, method: http.RequestMethod.POST, data, showLoading }) } // PUT putT(url: string, data?: Object, showLoading true) { return this.requestT({ url, method: http.RequestMethod.PUT, data, showLoading }) } // DELETE deleteT(url: string, data?: Object, showLoading true) { return this.requestT({ url, method: http.RequestMethod.DELETE, data, showLoading }) } } export default HttpUtil.getInstance()四、业务页面实战调用4.1 资讯列表页面GET 请求etsimport HttpUtil, { ResponseData } from ../utils/http_util interface NewsItem { id: number title: string } Entry Component struct NewsPage { State newsList: NewsItem[] [] async aboutToAppear() { await this.loadNews() } async loadNews() { const res await HttpUtil.getNewsItem[](/posts) if (res) { this.newsList res.data.slice(0, 10) } } build() { Column({ space: 10 }) { Text(网络请求资讯列表演示).fontSize(22).padding(12) List({ space: 10 }).layoutWeight(1) { ForEach(this.newsList, item { ListItem() { Text(item.title) .width(100%) .padding(16) .backgroundColor(Color.White) .borderRadius(10) } }) } } .width(100%) .height(100%) .backgroundColor(#f5f5f5) } aboutToDisappear() { // 页面退出取消所有请求防止内存泄漏 HttpUtil.clearAllRequest() } }4.2 登录页面POST 提交表单etsimport HttpUtil from ../utils/http_util import RouterUtil from ../utils/router_util import { STORAGE_KEY, PAGE_ROUTE } from ../model/Constant import AppStorage from ohos.arkui.state.AppStorage Entry Component struct LoginPage { State account: string State pwd: string async doLogin() { if (!this.account || !this.pwd) return const params { username: this.account, password: this.pwd } const res await HttpUtil.post{ token: string }(/login, params) if (res) { // 存储全局token AppStorage.Set(STORAGE_KEY.TOKEN, res.data.token) AppStorage.Set(STORAGE_KEY.IS_LOGIN, true) RouterUtil.replace(PAGE_ROUTE.INDEX) } } build() { Column({ space: 20 }) { Text(用户登录).fontSize(26).margin({ top: 60 }) TextInput({ text: this.account, placeholder: 账号 }).width(90%).height(48) TextInput({ text: this.pwd, placeholder: 密码 }).type(InputType.Password).width(90%).height(48) Button(登录).width(90%).height(48).onClick(() this.doLogin()) } .width(100%) .height(100%) .padding(20) } aboutToDisappear() { HttpUtil.clearAllRequest() } }五、文件上传扩展方法补充进 HttpUtilets// 表单文件上传 async uploadFileT(url: string, filePath: string, fileName: string) { const fullUrl BASE_URL url const token AppStorage.Getstring(STORAGE_KEY.TOKEN) const header: Recordstring, string {} if (token) header.Authorization Bearer ${token} let httpReq http.createHttp() requestPool.add(httpReq) promptAction.showLoading() try { // 表单参数 const formData: Arrayhttp.MultiFormData [ { name: file, filePath, fileName } ] const res await httpReq.request(fullUrl, { method: http.RequestMethod.POST, header, multiFormDataList: formData }) httpReq.destroy() requestPool.delete(httpReq) promptAction.closeLoading() if (res.responseCode ! 200) return null const result: ResponseDataT JSON.parse(res.result as string) return result } catch (e) { httpReq.destroy() requestPool.delete(httpReq) promptAction.closeLoading() promptAction.showToast({ message: 文件上传失败 }) return null } }六、API23 网络开发编码规范6.1 请求生命周期规范页面aboutToDisappear必须调用clearAllRequest()终止全部请求避免销毁页面后回调执行报错每个 HttpRequest 使用完毕执行 destroy 释放底层连接并发请求统一存入请求池统一管理销毁。6.2 拦截与业务处理规范请求拦截自动携带全局 token页面无需重复处理响应拦截统一处理 HTTP 状态码与后端业务 code401 自动清空登录跳转登录页全局 loading 自动弹出关闭减少页面重复弹窗代码。6.3 性能与网络适配规范统一设置超时 10s避免弱网无限等待频繁列表刷新增加防抖短时间重复请求直接取消上一次大文件上传拆分分片防止单次请求内存占用过高。6.4 安全规范线上正式环境关闭 cleartextTraffic 明文 http仅使用 httpstoken 存放 AppStorage退出登录清空敏感接口参数禁止拼接在 url统一使用 post extraData 传参。七、高频问题解决方案问题 1页面销毁后接口回调执行页面变量报错 解决页面退出调用 clearAllRequest 批量 abort 所有请求。问题 2接口 401 登录失效多处页面重复写跳转逻辑 解决工具内部统一捕获 code401自动清空登录状态并弹窗提示。问题 3多次快速点击按钮发起重复请求 解决增加 loading 状态锁加载期间拦截点击。问题 4文件上传图片无法识别 解决使用 multiFormDataList 表单上传传入本地沙盒文件完整路径。问题 5升级 API23 旧版 http 代码编译报错 解决替换废弃回调写法统一使用 async/await 异步请求手动 destroy 释放实例。问题 6弱网环境长时间卡死无提示 解决配置 connectTimeout、readTimeout超时自动抛出异常并提示用户。八、总结基于原生ohos.net.http封装的 axios 风格网络工具统一完成请求头注入、全局加载弹窗、响应数据解析、业务错误分发、页面销毁请求销毁、文件上传全套通用逻辑大幅简化页面网络交互代码。API23 完善 HttpRequest 中断与销毁机制解决旧版请求泄漏、弱网卡死、并发卡顿等问题可直接整合进前面整套四层架构项目是课程设计、毕设前后端交互核心底层工具。

相关新闻

玩转集成|告别繁琐!Slack中无缝启用Claude Code的完整指南与实战场景

玩转集成|告别繁琐!Slack中无缝启用Claude Code的完整指南与实战场景

1. 为什么要在Slack中使用Claude Code? 作为一名长期使用AI编程助手的开发者,我深刻体会到在团队协作环境中频繁切换工具的痛苦。每次遇到代码问题都要离开Slack去网页端操作,不仅打断工作流,还容易丢失上下文。Claude Code与Sla…

2026/7/15 1:56:41阅读更多 →
C语言中的exit()函数

C语言中的exit()函数

函数名: exit() 所在头文件:stdlib.h 功 能: 关闭所有文件,终止正在执行的进程。 exit(1)表示异常退出.这个1是返回给操作系统的。 exit(x)(x不为0)都表示异常退出 exit(0)表示正常退出 exit()的参数会被传递给一些操作系统&#…

2026/7/15 1:56:41阅读更多 →
MSP430FR59xx内存映射与寄存器操作实战指南

MSP430FR59xx内存映射与寄存器操作实战指南

1. 项目概述与核心价值如果你正在使用德州仪器(TI)的MSP430FR59xx系列微控制器,比如FR5972或FR5872,并且已经过了点灯、调通串口的入门阶段,那么你迟早会碰到一个绕不开的坎:内存映射和寄存器。这两个概念&…

2026/7/15 1:56:41阅读更多 →
WK2204 SPI转UART驱动移植与典型问题排查指南

WK2204 SPI转UART驱动移植与典型问题排查指南

1. WK2204芯片基础认知与硬件设计要点WK2204是成都为开微电子推出的一款工业级SPI转UART芯片,它能够通过SPI接口扩展出4个独立的全双工UART通道。在实际项目中,我发现这颗芯片有几个显著特点值得开发者关注:首先,每个子通道都具备…

2026/7/15 2:56:45阅读更多 →
TLK10031 PHY芯片数据切换与链路训练寄存器配置实战

TLK10031 PHY芯片数据切换与链路训练寄存器配置实战

1. 项目概述与核心价值在万兆以太网(10GbE)硬件设计领域,尤其是涉及背板互连、高速交换机和网络接口卡(NIC)时,PHY芯片的寄存器配置是决定系统成败的“灵魂”。这不仅仅是简单的参数设置,而是工…

2026/7/15 2:56:45阅读更多 →
【软考-中级】系统集成项目管理工程师-进度管理-关键路径法实战:从“顺推取大、逆推取小”到项目工期精准掌控

【软考-中级】系统集成项目管理工程师-进度管理-关键路径法实战:从“顺推取大、逆推取小”到项目工期精准掌控

1. 关键路径法:项目进度的"生命线"第一次接触关键路径法时,我盯着那张布满箭头的网络图发呆了半小时——这简直比地铁线路图还复杂!但当我真正理解它的核心逻辑后,才发现这简直是项目管理中的"导航系统"。就像…

2026/7/15 2:56:45阅读更多 →
PID整定实战:从临界比例法到现代优化策略的演进与对比

PID整定实战:从临界比例法到现代优化策略的演进与对比

1. PID控制基础与临界比例法实战PID控制器作为工业控制领域的"常青树",其核心在于比例(P)、积分(I)、微分(D)三个环节的协同作用。记得我第一次调试温控系统时,手动试凑参…

2026/7/15 2:56:45阅读更多 →
Modbus通讯协议(四)——基于Spring Boot与jlibmodbus构建高可用ModbusTCP从机服务

Modbus通讯协议(四)——基于Spring Boot与jlibmodbus构建高可用ModbusTCP从机服务

1. 为什么需要Spring Boot整合jlibmodbus?在工业物联网场景中,Modbus TCP从机服务常常需要与后台管理系统深度集成。传统Java实现方式存在三个典型痛点:一是生命周期管理困难,二是缺乏高可用保障,三是配置不够灵活。我…

2026/7/15 2:56:45阅读更多 →
从“55原则”到“1/6λ”:揭秘PCB高速信号的三大经典判据

从“55原则”到“1/6λ”:揭秘PCB高速信号的三大经典判据

1. 高速信号判据的工程密码刚入行PCB设计那会儿,我最头疼的就是判断什么时候该用高速设计规则。记得有次用双层板做了个100MHz的时钟电路,结果信号波形扭曲得像心电图,调试两周才发现是传输线效应在作怪。后来师父扔给我三个数字:…

2026/7/15 2:51:45阅读更多 →
VSCode TypeScript 环境配置对比:全局安装 vs 项目本地安装的4个关键差异

VSCode TypeScript 环境配置对比:全局安装 vs 项目本地安装的4个关键差异

VSCode TypeScript 环境配置对比:全局安装 vs 项目本地安装的4个关键差异当你在VSCode中启动一个新的TypeScript项目时,第一个技术决策往往从安装方式开始。这个看似简单的选择——全局安装还是项目本地安装——实际上会深刻影响你的开发流程、团队协作和…

2026/7/14 4:56:14阅读更多 →
智慧树刷课插件:5分钟实现自动化学习的智能助手

智慧树刷课插件:5分钟实现自动化学习的智能助手

智慧树刷课插件:5分钟实现自动化学习的智能助手 【免费下载链接】zhihuishu 智慧树刷课插件,自动播放下一集、1.5倍速度、无声 项目地址: https://gitcode.com/gh_mirrors/zh/zhihuishu 智慧树刷课插件是一款专为智慧树在线教育平台设计的Chrome浏…

2026/7/14 2:55:05阅读更多 →
Steam创意工坊下载器WorkshopDL:跨平台游戏模组获取的终极解决方案

Steam创意工坊下载器WorkshopDL:跨平台游戏模组获取的终极解决方案

Steam创意工坊下载器WorkshopDL:跨平台游戏模组获取的终极解决方案 【免费下载链接】WorkshopDL WorkshopDL - The Best Steam Workshop Downloader 项目地址: https://gitcode.com/gh_mirrors/wo/WorkshopDL 你是否在GOG或Epic Games Store购买了心仪的游戏…

2026/7/14 6:17:41阅读更多 →
AI框架决定企业AI能走多远

AI框架决定企业AI能走多远

企业AI建设的第一性原理 企业搞AI,最关键的决定是什么?不是选哪家大模型,不是先做哪个场景,不是招多少AI人才——而是选哪个AI开发框架。 为什么?因为框架决定了企业AI能力的"天花板"。选对了框架&#xff0…

2026/7/15 0:01:30阅读更多 →
Java企业为什么需要AI框架

Java企业为什么需要AI框架

Java企业在AI时代的尴尬处境 Java是全球企业级应用开发的主流语言——全球超过一半的企业系统跑在Java上。但在AI浪潮面前,很多Java企业感到尴尬:大模型的接口是各种语言的,AI开发社区以其他语言为主流,似乎Java在AI时代"掉队…

2026/7/15 0:01:30阅读更多 →
CC3230x嵌入式开发实战:SD主机、定时器与低功耗模式深度解析

CC3230x嵌入式开发实战:SD主机、定时器与低功耗模式深度解析

1. 项目概述:为什么需要关注CC3230x的SD主机、定时器与低功耗?在物联网和嵌入式设备开发领域,我们常常面临一个核心矛盾:设备需要具备强大的连接能力、可靠的数据存储和实时控制功能,同时又必须严格控制功耗以延长电池…

2026/7/15 0:01:30阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/14 15:07:30阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/14 4:45:36阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/14 2:42:17阅读更多 →