首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >HarmonyOS ArkTS 学习经历

HarmonyOS ArkTS 学习经历

原创
作者头像
with_me
发布于 2026-10-28 16:04:35
发布于 2026-10-28 16:04:35
1140
举报

#WorkBuddy# HarmonyOS ArkTS 实战:用 @ohos/axios 封装请求层,统一响应结构与 token 自动注入

环境:DevEco Studio + HarmonyOS SDK(targetSdkVersion 26 / compatibleSdkVersion 5.0.3(15)),Stage 模型,ArkTS + ArkUI 声明式写法。 网络库:@ohos/axios(社区维护的 ArkTS 版 axios,API 与 axios 基本一致)。 后端:Express + MySQL,约定统一返回 { code, msg, data }。 本文所有代码均来自我实际跑通的工程,IP 等环境信息已做脱敏处理。

一、要解决什么问题

用 ArkUI 写页面时,只要后端是 RESTful 风格,就一定会碰到这几个问题:

  1. 每个页面都要写 baseURL,改一次地址要改十处;
  2. 登录拿到 token 之后,后面每个请求都要手动塞 Authorization 头,漏一个就 401;
  3. 后端返回 { code, msg, data },但 axios 只会把 data 当成功,业务码得自己判断,容易漏;
  4. token 过期后没有任何统一处理逻辑,用户只能看着接口报错发呆。

所以这篇的核心目标只有一个:把"请求层"抽出来,让页面只关心业务。

二、最终目录结构

三、第一步:先把响应结构定义成类型

ArkTS 是强类型语言,把接口出入参先定义清楚,后面所有页面的提示都能自动补全,也能避免 any 满天飞。

model/LoginType.ets:

model/CityListType.ets:

命名上我用的是「请求类型 / 响应类型 / 响应数据类型」三级结构:*Request* 是入参,*Response* 是含 code/msg/data 的完整响应,*ResponseData* 是 data 内部真正的业务数据。这样在页面上 response.data.data 层层递进虽然多打几个字,但类型完全对得上。

四、第二步:封装 axios 实例 + 请求拦截器(关键)

新建 utils/MyAxios.ets:

三个要点:

  • axios.create() 返回实例,业务代码全部用 instance.get/post,不再直接 axios.get,地址只在这一处配置;
  • 请求拦截器统一注入 Authorization: Bearer <token>,token 从 AppStorage 里取,页面完全不用关心鉴权头;
  • AppStorage 是 HarmonyOS 的全局状态容器,AppStorage.set 写入后全应用任意页面都能读到,比自己造单例更贴合 ArkUI 的状态模型。

五、第三步:登录页拿到 token 并存进 AppStorage

pages/Index.ets:

@StorageLink vs @StorageProp 是这里最容易被忽略但很关键的一对:

装饰器

与 AppStorage 的关系

用在哪

@StorageLink

双向绑定,改页面值会写回 AppStorage,AppStorage 变了页面也会刷新

登录页(写入 token)

@StorageProp

单向同步,AppStorage 变了页面会刷新,但改页面值不会回写

列表页(只读用户名)

写反了就会出现"登录页写入的 token 列表页读不到"这类玄学问题。

六、第四步:列表页直接用,token 自动带上

pages/CityList.ets:

注意 instance.get('/api/cities') 这一行——代码里完全看不到 token,但请求头里一定有 Authorization,因为拦截器已经包掉了。这就是抽象请求层的价值:鉴权逻辑只写一次,以后加签名字段、加密、埋点都只改一个文件。

七、第五步:写入型接口 + 后端返回时间的本地化

新增城市 pages/CityAdd.ets:

后端返回的 update_time 是 2026-10-14T08:24:16.000Z 这种 ISO 串,直接显示很难看,我写了个格式化工具 utils/artTs.ets:

用正则只取日期部分,同时兼容 2026-10-14、2026/10/14、2026.10.14 三种分隔符,非法日期直接返回空串而不是崩掉。

八、我实际踩过的 5 个坑

坑 1:路由 url 少写一个 s,页面跳不过去

我最初写的是:

运行时直接报路由找不到。ArkUI 的路由 url 必须和 main_pages.json 里登记的路径完全一致,而登记的是 pages/CityList(目录名是 pages,不是 page)。改回来就好了。

坑 2:目标页面忘了登记进 main_pages.json

main_pages.json 是路由白名单,所有用 router.pushUrl 跳转的页面都必须在这里出现:

我另一个工程里写了 router.pushUrl({url:"pages/UserRegister"}),但 main_pages.json 里只有 "pages/Index",跳转直接失败。新建页面后第一件事:去 main_pages.json 登记。

坑 3:拦截器里 AppStorage.get 可能拿到 undefined

拦截器这段在用户还没登录时也会执行:

如果此时 AppStorage 里根本没有 userInfo 这个键,AppStorage.get 返回 undefined,强制类型断言不会改变运行时行为,紧接着取 .token 就会抛 Cannot read property 'token' of undefined,整个请求直接崩在拦截器里。

修法是加一层空值保护:

坑 4:timeout 设太小,请求莫名其妙失败

我一开始写 timeout: 500(毫秒),走真实网络时后端稍慢就超时。后调成 timeout: 2000 才稳定。内网自测不代表生产表现,超时值要按最慢接口来定。

坑 5:只写了请求拦截器,没有响应拦截器

现在的 MyAxios.ets 只处理了"发请求时加 token",但没处理"收响应时 token 过期"。后端返回 401 时,页面只会走进 .catch,用户看到的是一句无意义的报错。

建议补一个响应拦截器,统一处理鉴权失效:

九、另外几个实用经验

  • axios 泛型的三个参数顺序是 <响应数据类型, AxiosResponse<响应数据类型>, 请求数据类型>,写错位置 TS/ArkTS 立刻报类型不匹配。GET 没有请求体,第三参数传 null。
  • baseURL 要不要带 /api 需和请求路径对应。我另一个工程 baseURL 里带了 /api,请求路径就不能再写 /api/xxx,否则会拼成 /api/api/xxx。
  • ArkTS 不支持 any 和动态属性,接口返回的动态字段要显式声明 interface,否则 .ets 编译直接失败。
  • @State 存接口数据、@StorageLink/@StorageProp 存全局状态,两者混用容易出现"数据改了视图不刷新"。

十、小结

整套流程跑通后,页面上写请求就是一行:

地址统一、鉴权统一、类型统一、错误处理统一,后续加新接口基本是复制粘贴。后续我打算在这套请求层之上,用 startAbilityForResult 把登录独立成单独的 Ability,让登录页用 terminateSelfWithResult 把 token 回传给主 Ability,替代现在的全局 AppStorage 传递方式——这也是我下一步要啃的 Ability Kit 实践。


本文代码均为实际工程实现,环境信息已脱敏。欢迎交流指正。 #WorkBuddy# #HarmonyOS# #ArkTS# #ohos-axios

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • #WorkBuddy# HarmonyOS ArkTS 实战:用 @ohos/axios 封装请求层,统一响应结构与 token 自动注入
    • 一、要解决什么问题
    • 二、最终目录结构
    • 三、第一步:先把响应结构定义成类型
    • 四、第二步:封装 axios 实例 + 请求拦截器(关键)
    • 五、第三步:登录页拿到 token 并存进 AppStorage
    • 六、第四步:列表页直接用,token 自动带上
    • 七、第五步:写入型接口 + 后端返回时间的本地化
    • 八、我实际踩过的 5 个坑
      • 坑 1:路由 url 少写一个 s,页面跳不过去
      • 坑 2:目标页面忘了登记进 main_pages.json
      • 坑 3:拦截器里 AppStorage.get 可能拿到 undefined
      • 坑 4:timeout 设太小,请求莫名其妙失败
      • 坑 5:只写了请求拦截器,没有响应拦截器
    • 九、另外几个实用经验
    • 十、小结
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档