OpenHarmony 网络请求全实战:Fetch/Http 双方案 + 全局请求封装 + 拦截器 + 统一异常处理

📅 2026/7/25 2:35:28
OpenHarmony 网络请求全实战:Fetch/Http 双方案 + 全局请求封装 + 拦截器 + 统一异常处理
一、前言前面系列教程覆盖了鸿蒙 UI 布局、路由、状态管理、本地存储、动画、权限、完整备忘录项目而网络请求是 APP 对接后端接口、实现线上数据交互的核心能力几乎所有商用 APP 都离不开网络调用。OpenHarmony 原生提供两套网络请求方案适配不同开发场景fetch推荐首选语法简洁、异步原生支持、轻量无冗余适合绝大多数业务接口请求http 模块底层更灵活支持请求超时配置、请求头精细管控、长连接适合复杂接口、大文件上传下载本文避开零散 demo直接从网络权限配置、原生基础请求、全局统一请求封装、请求 / 响应拦截器、超时重试、统一异常捕获、文件上传下载、线上接口实战全覆盖封装可直接用于企业项目的网络工具类解决原生网络请求痛点代码冗余、异常分散、无统一 loading、无超时处理、重复请求无法拦截。二、前置准备网络权限配置必配2.1 module.json5 网络权限声明鸿蒙应用默认禁止网络访问必须手动声明网络权限否则直接请求报错无任何网络回调。jsonrequestPermissions: [ { name: ohos.permission.INTERNET, reason: 应用访问网络接口、获取线上数据, usedScene: { abilities: [EntryAbility], when: inuse } } ]2.2 明文 http 请求配置测试必备开发阶段大量接口为 http 明文协议鸿蒙默认禁止明文网络请求需要在 module.json5 增加网络安全配置放开 http 限制jsonnetwork: { cleartextTraffic: true }三、两套原生网络 API 基础用法对比3.1 Fetch 基础请求GET/POSTfetch 语法贴近前端原生语法上手零成本默认支持 Promise 异步调用日常接口优先使用。ets// GET请求-获取列表数据 async function fetchGetDemo() { let res await fetch(https://jsonplaceholder.typicode.com/todos/1) let data await res.json() console.log(GET请求结果, JSON.stringify(data)) } // POST请求-提交表单数据 async function fetchPostDemo() { let res await fetch(https://jsonplaceholder.typicode.com/posts,{ method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ title: 鸿蒙网络测试, body: fetch post请求测试, userId: 1 }) }) let data await res.json() console.log(POST请求结果, JSON.stringify(data)) }3.2 http 模块基础请求支持超时原生 fetch 不支持直接设置超时时间http 模块原生支持超时、请求取消稳定性更强。etsimport http from ohos.net.http async function httpGetDemo() { // 创建http请求实例 let httpReq http.createHttp() // 设置超时时间 8000ms httpReq.requestTimeout 8000 let res await httpReq.request(https://jsonplaceholder.typicode.com/todos/1,http.RequestMethod.GET) console.log(http请求结果, res.result) // 请求结束销毁实例避免内存泄漏 httpReq.destroy() }四、企业级全局网络工具类完整版直接复制可用整合 GET/POST、统一请求头、超时拦截、异常捕获、全局 Loading、请求拦截、响应拦截项目直接复用。etsimport http from ohos.net.http import promptAction from ohos.promptAction // 全局基础域名 const BASE_URL https://jsonplaceholder.typicode.com // 请求超时时间 const TIME_OUT 8000 class HttpRequest { // 请求拦截器统一添加token、请求头 private requestInterceptor(options: any) { options.header { Content-Type: application/json;charsetUTF-8, // 自动携带登录token token: AppStorage.get(token) || , ...options.header } return options } // 响应拦截器统一处理状态码、后端错误码 private responseInterceptor(res: http.HttpResponse): any { // 网络状态码判断 if (res.responseCode ! 200) { promptAction.showToast({message:网络请求异常请稍后重试}) return null } return res.result } // 核心请求方法 async request(url:string, method:http.RequestMethod, data:any {}, options:any {}) { // 执行请求拦截 let reqOptions this.requestInterceptor(options) // 拼接完整接口地址 let fullUrl BASE_URL url // 创建请求实例 let httpClient http.createHttp() httpClient.requestTimeout TIME_OUT try { promptAction.showLoading({message:加载中...}) let res await httpClient.request(fullUrl, method, { extraData: data, header: reqOptions.header }) promptAction.dismissLoading() // 响应拦截处理 return this.responseInterceptor(res) } catch (err) { promptAction.dismissLoading() // 统一捕获超时、断网、服务器异常 promptAction.showToast({message:网络异常或请求超时}) console.error(网络请求失败,err) return null } finally { // 销毁实例释放资源 httpClient.destroy() } } // 封装GET请求 get(url:string, params?:any) { return this.request(url, http.RequestMethod.GET, params) } // 封装POST请求 post(url:string, data?:any) { return this.request(url, http.RequestMethod.POST, data) } } // 全局单例导出 export default new HttpRequest()五、页面直接调用极简调用方式etsimport HttpRequest from ../utils/HttpRequest Entry Component struct NetworkDemoPage { State resultText:string // 调用GET接口 async getNetData() { let res await HttpRequest.get(/todos/1) this.resultText JSON.stringify(res) } // 调用POST接口 async postNetData() { let res await HttpRequest.post(/posts,{ title:鸿蒙网络封装测试, content:统一请求工具类调用成功 }) this.resultText JSON.stringify(res) } build() { Column({space:20}) { Button(发起GET网络请求).onClick(()this.getNetData()) Button(发起POST网络请求).onClick(()this.postNetData()) Text(this.resultText).fontSize(14).padding(15).width(90%) } .width(100%) .height(100%) .justifyContent(FlexAlign.Center) } }六、进阶功能请求防抖 重复请求拦截防止用户快速点击按钮短时间多次发起相同请求造成接口重复调用ets// 存储正在请求的接口地址 let pendingUrlList:string[] [] // 请求前拦截重复请求 function checkPending(url:string):boolean { if(pendingUrlList.includes(url)){ promptAction.showToast({message:请勿重复请求}) return true } pendingUrlList.push(url) return false } // 请求结束移除记录 function removePending(url:string) { let index pendingUrlList.indexOf(url) if(index -1){ pendingUrlList.splice(index,1) } }七、网络请求开发踩坑大全忘记配置网络权限不报代码错误接口始终无返回必须配置ohos.permission.INTERNEThttp 请求被拦截真机默认禁止明文 http必须开启cleartextTraffic:truehttp 实例不销毁频繁请求不调用 destroy会造成严重内存泄漏无超时处理网络差时页面一直 loading必须统一配置超时时间缺少异常捕获断网、服务器崩溃直接页面白屏必须 try-catch 全局捕获重复请求按钮高频点击重复发请求需要做请求队列拦截八、Fetch 与 Http 选型建议日常业务接口优先用 fetch代码简洁快速开发需要超时 / 取消请求必选 http 原生模块企业项目统一开发直接封装 http 工具类统一拦截、统一异常、统一 loading适配全业务