news 2026/9/24 14:13:52

鸿蒙网络请求封装:基于 Axios 开发一个支持“自动刷新 Token”的 HTTP 客户端

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
鸿蒙网络请求封装:基于 Axios 开发一个支持“自动刷新 Token”的 HTTP 客户端

标签:#HarmonyOS #Axios #网络请求 #ArkTS #Token刷新 #架构设计


📉 前言:为什么原生 http 模块不够用?

原生http.createHttp()的痛点:

  1. 代码冗余:每次都要写extraDataconnectTimeout,还要手动解析 JSON。
  2. 缺乏拦截器:想给所有请求统一加 Header 或者统一处理错误,只能写个包装函数,很难维护。
  3. 类型弱:返回的数据全是string,需要手动JSON.parse并断言类型。

引入@ohos/axios后,我们不仅能复用前端的拦截器思维,还能利用 ArkTS 的泛型系统实现类型安全的网络层


🏗️ 一、 核心逻辑:Token 自动刷新流程

这是本篇的重难点。当多个并发请求同时触发 401 时,我们不能发起多次刷新请求,而是应该加锁。

并发控制流程图 (Mermaid):

401 未授权?

否 (我是第一个)

调用刷新接口

是 (别人正在刷)

刷新成功

解锁 & 广播

重发

刷新失败 (过期)

发起请求 A, B, C

响应拦截器

当前是否正在刷新?

加锁: isRefreshing = true

换取新 AccessToken

加入等待队列 (Promise Pending)

保存新 Token

执行队列中的请求

重发请求 A

强制登出

请求成功


🛠️ 二、 环境准备

安装鸿蒙版 Axios:

ohpminstall@ohos/axios

💻 三、 代码实战:企业级封装

我们新建一个AxiosRequest.ts文件。

1. 定义基础结构与类型

为了让调用者用得爽,我们先定义好返回结构。

importaxios,{AxiosInstance,AxiosRequestConfig,AxiosResponse,AxiosError}from'@ohos/axios';// 后端返回的标准结构interfaceBaseResponse<T>{code:number;message:string;data:T;}// 扩展 Axios 配置,允许传递自定义参数(如:是否需要 Loading)interfaceCustomRequestConfigextendsAxiosRequestConfig{showLoading?:boolean;}
2. 实现单例类与请求拦截

请求拦截器的作用很简单:有 Token 就带上

classAxiosHttpRequest{privateinstance:AxiosInstance;constructor(){this.instance=axios.create({baseURL:'https://api.example.com/v1',timeout:10000,headers:{'Content-Type':'application/json'}});// --- 请求拦截器 ---this.instance.interceptors.request.use((config:CustomRequestConfig)=>{// 从 AppStorage 或 Preferences 获取 Tokenconsttoken=AppStorage.Get<string>('accessToken');if(token){config.headers['Authorization']=`Bearer${token}`;}returnconfig;},(error)=>Promise.reject(error));// 响应拦截器在下一步实现...}}
3. 核心:响应拦截与无感刷新 (The Magic)

这里我们需要两个辅助变量:

  • isRefreshing: 防止多次调用刷新接口。
  • requestsQueue: 存储在刷新期间进来的其他请求。
// ... 类内部变量privateisRefreshing=false;privaterequestsQueue:Function[]=[];// ... 在 constructor 中继续添加响应拦截器this.instance.interceptors.response.use((response:AxiosResponse)=>{// 这里的逻辑根据你们后端业务码来定// 假设 http status 200 但 code 401 也是 token 过期constres=response.dataasBaseResponse<any>;if(res.code===401){returnthis.handle401Error(response.config);}returnresponse;},(error:AxiosError)=>{// 处理 HTTP 状态码为 401 的情况if(error.response?.status===401){returnthis.handle401Error(error.config);}returnPromise.reject(error);});// --- 处理 401 的核心逻辑 ---privatehandle401Error(originConfig:AxiosRequestConfig){if(!this.isRefreshing){this.isRefreshing=true;// 1. 发起刷新 Token 请求 (注意:这里最好用一个新的 axios 实例,避免死循环)returnthis.refreshToken().then((newToken)=>{// 2. 刷新成功,保存新 TokenAppStorage.SetOrCreate('accessToken',newToken);// 3. 修改原请求的 HeaderoriginConfig.headers['Authorization']=`Bearer${newToken}`;// 4. 执行队列中的请求this.requestsQueue.forEach(cb=>cb(newToken));this.requestsQueue=[];// 5. 重发当前请求returnthis.instance(originConfig);}).catch((err)=>{// 6. 刷新也失败了?那是真的过期了,去登录页吧this.requestsQueue=[];// router.pushUrl({ url: 'pages/Login' })returnPromise.reject(err);}).finally(()=>{this.isRefreshing=false;});}else{// 如果正在刷新,则把当前请求挂起,放入队列returnnewPromise((resolve)=>{this.requestsQueue.push((newToken:string)=>{originConfig.headers['Authorization']=`Bearer${newToken}`;resolve(this.instance(originConfig));});});}}// 模拟刷新 Token 的接口privateasyncrefreshToken():Promise<string>{// 实际业务中这里调用后端刷新接口// const refreshToken = AppStorage.Get('refreshToken');return"new_generated_token_123";}
4. 封装便捷方法 (GET/POST)

最后,暴露简单易用的 API。

// T 是返回数据的类型,D 是请求参数的类型publicget<T>(url:string,params?:any):Promise<T>{returnthis.instance.get<BaseResponse<T>>(url,{params}).then(res=>res.data.data);}publicpost<T>(url:string,data?:any):Promise<T>{returnthis.instance.post<BaseResponse<T>>(url,data).then(res=>res.data.data);}}// 导出单例exportconsthttp=newAxiosHttpRequest();

🚀 四、 调用演示:丝滑体验

在你的 UI 组件 (.ets) 中:

import{http}from'../utils/AxiosRequest';interfaceUserProfile{id:number;name:string;}@Entry@Componentstruct ProfilePage{@Stateuser:UserProfile|null=null;asyncaboutToAppear(){try{// 泛型支持:res 自动推断为 UserProfile 类型// 哪怕 Token 过期,这里也会自动重试并成功返回constres=awaithttp.get<UserProfile>('/user/profile');this.user=res;console.info('用户名称:',res.name);}catch(error){console.error('请求失败:',error);}}build(){// UI ...}}

🎯 总结

通过这次封装,我们实现了:

  1. 代码解耦:UI 层不需要关心 Token 怎么传,也不需要关心 401 怎么处理。
  2. 类型安全:利用 TypeScript 泛型,接口返回什么类型,代码里就是什么类型。
  3. 极致体验Request Queue (请求队列)的设计,确保了在并发请求场景下,Token 刷新接口只会被调用一次,避免了资源浪费和逻辑错误。

这是鸿蒙 App 开发中性价比最高的基建工作之一。

Next Step:
现在的封装还没处理Loading 动画。试着修改Interceptor,在请求开始时调用promptAction.showToast或自定义 Loading 组件,请求结束时关闭它,实现全局自动 Loading。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/22 2:25:25

Rembg抠图在电商详情页优化中的实践

Rembg抠图在电商详情页优化中的实践 1. 引言&#xff1a;智能万能抠图 - Rembg 在电商行业&#xff0c;商品详情页的视觉呈现直接影响转化率。高质量的商品图片&#xff0c;尤其是具备透明背景的PNG图像&#xff0c;能够显著提升页面的专业度和用户体验。然而&#xff0c;传统…

作者头像 李华
网站建设 2026/9/23 6:34:47

TESTSIGMA:AI如何革新自动化测试开发

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 创建一个基于TESTSIGMA平台的AI辅助测试开发演示项目。项目需要展示如何使用自然语言描述测试场景&#xff0c;自动生成可执行的测试脚本。包含以下功能&#xff1a;1) 使用自然语…

作者头像 李华
网站建设 2026/9/22 1:49:52

AI万能分类器故障排查:常见问题与解决方案

AI万能分类器故障排查&#xff1a;常见问题与解决方案 1. 引言 1.1 背景与痛点 在构建智能文本处理系统时&#xff0c;传统分类模型往往需要大量标注数据和漫长的训练周期。为解决这一问题&#xff0c;AI万能分类器应运而生——基于StructBERT的零样本&#xff08;Zero-Shot…

作者头像 李华
网站建设 2026/9/12 5:58:28

AI万能分类器实战:智能客服意图识别系统部署教程

AI万能分类器实战&#xff1a;智能客服意图识别系统部署教程 1. 引言 在智能客服、工单处理和用户反馈分析等场景中&#xff0c;意图识别是实现自动化响应的核心能力。传统方法依赖大量标注数据进行模型训练&#xff0c;开发周期长、维护成本高。随着大模型技术的发展&#x…

作者头像 李华
网站建设 2026/9/21 0:38:28

Rembg抠图应用:企业宣传册设计指南

Rembg抠图应用&#xff1a;企业宣传册设计指南 1. 智能万能抠图 - Rembg 在企业宣传册、产品目录和品牌视觉设计中&#xff0c;高质量的图像素材是提升专业度与吸引力的核心要素。然而&#xff0c;传统图像去背景方式依赖人工精修或半自动工具&#xff0c;耗时长、成本高&…

作者头像 李华
网站建设 2026/9/18 8:24:19

快速验证:自制WSL卸载检查工具开发实录

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 开发一个轻量级WSL状态检查工具原型&#xff0c;功能&#xff1a;1) 快速检测WSL安装状态 2) 显示已安装发行版 3) 一键跳转到卸载界面 4) 基本系统要求检查。使用HTML/JS开发单页…

作者头像 李华