OpenHarmony 网络请求全实战:Fetch/Http 双方案 + 全局请求封装 + 拦截器 + 统一异常处理一、前言
·
一、前言
前面系列教程覆盖了鸿蒙 UI 布局、路由、状态管理、本地存储、动画、权限、完整备忘录项目,而网络请求是 APP 对接后端接口、实现线上数据交互的核心能力,几乎所有商用 APP 都离不开网络调用。
OpenHarmony 原生提供两套网络请求方案,适配不同开发场景:
- fetch(推荐首选):语法简洁、异步原生支持、轻量无冗余,适合绝大多数业务接口请求
- http 模块:底层更灵活,支持请求超时配置、请求头精细管控、长连接,适合复杂接口、大文件上传下载
本文避开零散 demo,直接从网络权限配置、原生基础请求、全局统一请求封装、请求 / 响应拦截器、超时重试、统一异常捕获、文件上传下载、线上接口实战全覆盖,封装可直接用于企业项目的网络工具类,解决原生网络请求痛点:代码冗余、异常分散、无统一 loading、无超时处理、重复请求无法拦截。
二、前置准备:网络权限配置(必配)
2.1 module.json5 网络权限声明
鸿蒙应用默认禁止网络访问,必须手动声明网络权限,否则直接请求报错,无任何网络回调。
json
"requestPermissions": [
{
"name": "ohos.permission.INTERNET",
"reason": "应用访问网络接口、获取线上数据",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
}
]
2.2 明文 http 请求配置(测试必备)
开发阶段大量接口为 http 明文协议,鸿蒙默认禁止明文网络请求,需要在 module.json5 增加网络安全配置,放开 http 限制:
json
"network": {
"cleartextTraffic": true
}
三、两套原生网络 API 基础用法对比
3.1 Fetch 基础请求(GET/POST)
fetch 语法贴近前端原生语法,上手零成本,默认支持 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 模块原生支持超时、请求取消,稳定性更强。
ets
import 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、请求拦截、响应拦截,项目直接复用。
ets
import 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;charset=UTF-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()
五、页面直接调用(极简调用方式)
ets
import 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.INTERNET - http 请求被拦截:真机默认禁止明文 http,必须开启
cleartextTraffic:true - http 实例不销毁:频繁请求不调用 destroy,会造成严重内存泄漏
- 无超时处理:网络差时页面一直 loading,必须统一配置超时时间
- 缺少异常捕获:断网、服务器崩溃直接页面白屏,必须 try-catch 全局捕获
- 重复请求:按钮高频点击重复发请求,需要做请求队列拦截
八、Fetch 与 Http 选型建议
- 日常业务接口:优先用 fetch,代码简洁,快速开发
- 需要超时 / 取消请求:必选 http 原生模块
- 企业项目统一开发:直接封装 http 工具类,统一拦截、统一异常、统一 loading,适配全业务
更多推荐


所有评论(0)