1. 项目概述:ArkTS 网络请求封装的意义与价值
在 HarmonyOS ArkTS 应用开发中,网络请求作为连接前后端数据的关键桥梁,其稳定性和开发效率直接影响项目进度和质量。原生 @ohos/axios 虽然功能完善,但直接使用存在明显的工程化缺陷:每个请求都需要重复配置基础参数、缺乏类型安全保障、错误处理逻辑分散等问题。通过封装类型安全的请求工具,我们能够实现:
- 开发效率提升:减少 60% 以上的重复配置代码
- 错误率降低:类型系统在编译阶段拦截 80% 以上的参数错误
- 维护成本优化:统一修改点从数十个业务文件缩减到 1 个工具类
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心架构设计解析
2.1 分层设计理念
采用经典的三层架构设计:
code复制业务层(页面组件)
↓
服务层(HttpClient 封装)
↓
基础层(axios 实例)
2.2 类型系统实现方案
通过 TypeScript 泛型实现双向类型约束:
typescript复制class HttpClient {
request<Res, Req = object>(config: AxiosRequestConfig<Req>): Promise<Res> {
// 实现逻辑
}
}
类型参数说明:
Res:强制指定响应数据类型,确保业务代码获得准确类型提示Req:可选指定请求参数类型,默认使用object类型
3. 关键实现细节详解
3.1 基础实例配置优化
typescript复制const instance: AxiosInstance = axios.create({
baseURL: 'https://api.example.com',
timeout: 10000,
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
})
配置要点:
- 超时时间根据业务场景调整(建议 10-30 秒)
- 开启
withCredentials需要后端配合 CORS 配置 - 生产环境建议通过环境变量动态设置 baseURL
3.2 拦截器深度定制
请求拦截器实现
typescript复制instance.interceptors.request.use(config => {
// 自动添加认证令牌
const token = AppStorage.get('token')
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
// 请求参数预处理
if (config.data && config.method === 'post') {
config.data = JSON.stringify(config.data)
}
return config
})
响应拦截器最佳实践
typescript复制instance.interceptors.response.use(
response => {
// 业务成功码判断
if (response.data.code === 0) {
return response.data.data
}
// 业务异常处理
const error = new Error(response.data.message)
error.code = response.data.code
return Promise.reject(error)
},
error => {
// 网络级错误处理
if (error.code === 'ECONNABORTED') {
error.message = '请求超时,请检查网络连接'
}
return Promise.reject(error)
}
)
4. 高级功能扩展方案
4.1 请求取消机制
typescript复制class HttpClient {
private cancelTokenMap = new Map<string, CancelTokenSource>()
cancelRequest(key: string) {
const source = this.cancelTokenMap.get(key)
source?.cancel(`手动取消请求: ${key}`)
}
get<Res>(url: string, config?: { cancelKey?: string }) {
if (config?.cancelKey) {
this.cancelRequest(config.cancelKey)
const source = axios.CancelToken.source()
this.cancelTokenMap.set(config.cancelKey, source)
return this.request<Res>({
url,
cancelToken: source.token
})
}
// 正常请求逻辑
}
}
使用场景:
- 页面跳转时取消未完成请求
- 防止表单重复提交
- 长列表分页请求的时序控制
4.2 文件上传特殊处理
针对文件上传需要单独处理请求头:
typescript复制const uploadFile = (file: File) => {
const formData = new FormData()
formData.append('file', file)
return httpClient.request<UploadResult>({
method: 'POST',
url: '/upload',
data: formData,
headers: {
'Content-Type': 'multipart/form-data'
}
})
}
注意事项:
- 自动生成的 boundary 无需手动设置
- 大文件上传建议实现分片上传逻辑
- 进度监听可通过
onUploadProgress配置项实现
5. 性能优化策略
5.1 请求缓存实现
typescript复制const cache = new Map<string, {
data: any
timestamp: number
}>()
const CACHE_TIME = 5 * 60 * 1000 // 5分钟缓存
async function getWithCache<Res>(url: string) {
const cached = cache.get(url)
if (cached && Date.now() - cached.timestamp < CACHE_TIME) {
return cached.data as Res
}
const res = await httpClient.get<Res>(url)
cache.set(url, {
data: res,
timestamp: Date.now()
})
return res
}
适用场景:
- 静态配置数据
- 实时性要求不高的列表数据
- 地理位置等低频变更信息
5.2 并发请求控制
typescript复制class RequestQueue {
private maxConcurrent = 5
private runningCount = 0
private queue: (() => Promise<void>)[] = []
async add<T>(task: () => Promise<T>): Promise<T> {
return new Promise((resolve, reject) => {
const wrappedTask = async () => {
this.runningCount++
try {
const result = await task()
resolve(result)
} catch (error) {
reject(error)
} finally {
this.runningCount--
this.runNext()
}
}
this.queue.push(wrappedTask)
this.runNext()
})
}
private runNext() {
while (this.runningCount < this.maxConcurrent && this.queue.length) {
const task = this.queue.shift()!
task()
}
}
}
6. 错误处理最佳实践
6.1 错误分类策略
typescript复制enum ErrorType {
NETWORK = 'network', // 网络错误
TIMEOUT = 'timeout', // 请求超时
BUSINESS = 'business', // 业务逻辑错误
AUTH = 'auth', // 认证失败
SYSTEM = 'system' // 系统异常
}
function handleError(error: any) {
let type = ErrorType.SYSTEM
let message = '系统异常'
if (error.code === 'ECONNABORTED') {
type = ErrorType.TIMEOUT
message = '请求超时'
} else if (!navigator.onLine) {
type = ErrorType.NE
