网络请求库:封装OkHttp/Retrofit风格的ArkTS网络库(226) 在鸿蒙HarmonyOS原生开发中官方并未直接提供类似 Android 的 OkHttp 或 Retrofit 库。但开发者可以借鉴其核心设计思想基于鸿蒙官方的kit.NetworkKit或ohos.net.http模块结合 ArkTS 的语法优势封装出高内聚、低耦合的生产级网络请求架构。一、 核心设计理念与架构分层优秀的网络库封装应遵循“高内聚、低耦合”原则通常划分为四个核心层级业务层页面或 Ability 直接调用语义化的 API如userApi.getUser()无需关心网络细节。客户端层HttpClient统一入口负责编排拦截器、重试逻辑和请求取消。能力层包含拦截器链InterceptorChain、重试引擎RetryPolicy和取消控制器CancelToken各模块单一职责。执行层最终调用鸿蒙原生http.createHttp().request()API。二、 声明式 API 与 Builder 模式为了达到类似 Retrofit 的优雅调用体验ArkTS 网络库通常采用 Builder 模式构造请求并支持链式调用。// 优雅的链式调用示例 const loginData: LoginRequest { username: admin, password: 123456 }; const response await httpClient.post(/auth/login) .json(loginData) // 设置 JSON 请求体 .timeout(5000) // 设置超时时间 .onProgress((loaded, total) console.log(${loaded}/${total})) // 进度回调 .executeApiResponseAuthTokenModel(); // 泛型执行并自动解析三、 拦截器链机制核心能力拦截器用于统一处理每个请求的公共逻辑如注入 Token、打印日志、统一错误处理将业务代码与网络逻辑彻底解耦。// 拦截器接口定义 interface RequestInterceptor { intercept(config: RequestConfig): PromiseRequestConfig; } // 鉴权拦截器示例自动为请求头注入 Token class AuthInterceptor implements RequestInterceptor { async intercept(config: RequestConfig): PromiseRequestConfig { const token await TokenManager.getToken(); if (token) { config.headers[Authorization] Bearer ${token}; } return config; } }四、 类型安全与泛型响应解析ArkTS 是强类型语言网络库必须摒弃any或unknown通过泛型T约束响应数据类型在编译期即可发现字段映射错误。// 统一的响应数据模型 interface ApiResponseT { code: number; message: string; data: T; } // 在业务层安全地获取强类型数据 const user await httpClient.get(/users/123).executeUser(); console.log(user.name); // 编译期类型安全无运行时风险五、 错误分类与重试机制生产级网络库需对异常进行精细化分类如网络断开、超时、401未授权、500服务器错误并配合指数退避算法实现自动重试。// 错误分类处理器示例 class ErrorHandler { static classify(error: BusinessError): string { const msg error.message.toLowerCase(); if (msg.includes(network)) return NETWORK; if (msg.includes(timeout)) return TIMEOUT; if (msg.includes(401) || msg.includes(403)) return AUTH; return UNKNOWN; } } // 结合重试引擎当发生 NETWORK 或 TIMEOUT 时自动进行最多3次的指数退避重试1s - 2s - 4s六、 生命周期绑定与内存防泄漏原生HttpRequest对象如果忘记销毁会导致内存泄漏。封装的网络库应内置自动销毁机制并提供CancelToken将请求与页面生命周期绑定如页面销毁时自动取消未完成的请求。七、 工程化落地建议优先使用原生封装对于企业级项目建议基于原生 API 深度定制这样能完全掌控底层行为且无第三方依赖风险。轻量级第三方替代如果项目体量较小希望快速接入可以直接使用鸿蒙生态中成熟的第三方库ohos/axios它提供了与前端一致的 Promise 链式调用体验。真机环境验证鸿蒙网络请求在真机上受权限、证书校验需配置network-security-config.xml及系统版本影响较大务必在多台真机上验证超时与重试策略的有效性。八、 完整实战代码构建生产级 ArkTS 网络请求库为了将上述架构设计落地以下是基于 ArkTS 构建的完整网络请求库代码。该实现涵盖了配置中心、拦截器链、泛型解析以及生命周期自动销毁机制。1. 核心配置与类型定义集中管理基础 URL、超时时间、默认 Headers 以及统一的响应数据结构确保全局配置的高内聚。// src/config/httpConfig.ts export const BASE_URL https://api.example.com/v1; export const TIMEOUT 10000; // 默认10秒超时 export const DEFAULT_HEADERS: Recordstring, string { Content-Type: application/json }; // 统一后端响应结构 export interface ApiResponseT { code: number; message: string; data: T; }2. 核心网络服务类 (HttpService)采用单例模式与 Builder 思想封装原生的http.createHttp()实现请求拦截、响应解析与自动销毁。// src/service/HttpService.ts import { http } from kit.NetworkKit; import { BASE_URL, TIMEOUT, DEFAULT_HEADERS, ApiResponse } from ../config/httpConfig; export class HttpService { private static instance: HttpService; private constructor() {} public static getInstance(): HttpService { if (!HttpService.instance) { HttpService.instance new HttpService(); } return HttpService.instance; } /** * 核心请求方法 * param method 请求方法 * param url 相对路径 * param data 请求体或查询参数 */ public async requestT( method: http.RequestMethod, url: string, data?: Object ): PromiseT { const httpRequest http.createHttp(); try { // 1. 组装最终请求头可在此处注入拦截器逻辑如 Token const headers { ...DEFAULT_HEADERS }; // 模拟鉴权拦截器 const token mock-jwt-token; if (token) headers[Authorization] Bearer ${token}; // 2. 配置请求参数 const options: http.HttpRequestOptions { method: method, header: headers, readTimeout: TIMEOUT, connectTimeout: TIMEOUT, expectDataType: http.HttpDataType.STRING }; // POST/PUT 请求携带 JSON Body if (data (method http.RequestMethod.POST || method http.RequestMethod.PUT)) { options.extraData JSON.stringify(data); } // 3. 发起请求 const response await httpRequest.request(${BASE_URL}${url}, options); // 4. 统一响应解析与业务异常处理 if (response.responseCode http.ResponseCode.OK) { const result JSON.parse(response.result as string) as ApiResponseT; if (result.code 200) { return result.data; } // 抛出业务级错误 throw new Error(Business Error: ${result.message}); } else { throw new Error(HTTP Error: ${response.responseCode}); } } catch (err) { // 5. 统一错误捕获 throw err; } finally { // 【关键】请求结束后无论成功失败立即销毁实例防止内存泄漏 httpRequest.destroy(); } } // 快捷方法封装 public getT(url: string, params?: Object): PromiseT { return this.requestT(http.RequestMethod.GET, url, params); } public postT(url: string, data?: Object): PromiseT { return this.requestT(http.RequestMethod.POST, url, data); } }3. 业务层 API 定义与页面调用将网络请求与 UI 彻底解耦在页面中只需关注数据获取与状态渲染。// src/pages/UserProfilePage.ets import { HttpService } from ../service/HttpService; interface User { id: number; name: string; email: string; } Entry Component struct UserProfilePage { State user: User | null null; State loading: boolean true; async aboutToAppear() { try { // 强类型调用IDE 提供完整的代码提示 this.user await HttpService.getInstance().getUser(/users/123); } catch (error) { console.error(获取用户信息失败:, (error as Error).message); } finally { this.loading false; } } build() { Column() { if (this.loading) { LoadingProgress() } else if (this.user) { Text(this.user.name).fontSize(24).fontWeight(FontWeight.Bold) Text(this.user.email).fontSize(16).fontColor(Color.Gray) } else { Text(加载失败).fontColor(Color.Red) } } .width(100%) .height(100%) .justifyContent(FlexAlign.Center) } }九、 进阶扩展页面级请求取消CancelToken在实际开发中用户快速切换页面时前一个页面的请求如果仍在后台执行可能会导致状态错乱或内存泄漏。可以通过扩展AbortController实现请求取消。// 在 HttpService 的 request 方法中增加取消支持 public async requestWithCancelT( method: http.RequestMethod, url: string, signal: AbortSignal ): PromiseT { const httpRequest http.createHttp(); // 监听取消信号 signal.onabort () { httpRequest.destroy(); }; // 执行请求逻辑... (同上) return this.requestT(method, url); } // 在组件中使用 Component struct SearchPage { private abortController new AbortController(); aboutToDisappear(): void { // 页面销毁时自动取消未完成的网络请求 this.abortController.abort(); } doSearch() { HttpService.getInstance().requestWithCancel( http.RequestMethod.GET, /search, this.abortController.signal ); } }