HarmonyOS宠物邻里实战第7篇:ArkTS前后端联调、ApiClient封装与错误排查清单

📅 2026/7/6 13:51:38
HarmonyOS宠物邻里实战第7篇:ArkTS前后端联调、ApiClient封装与错误排查清单
HarmonyOS宠物邻里实战第7篇ArkTS前后端联调、ApiClient封装与错误排查清单摘要HarmonyOS App 写到一定复杂度后前后端联调会成为真正影响效率的地方。宠物邻里项目里前端不是只有静态页面而是要对接宠物档案、社区帖子、寄养需求、通知、账号安全等后端接口。如果每个页面都自己拼 URL、自己处理错误、自己判断登录态后期会很难维护。本文基于宠物邻里 HarmonyOS 项目复盘 ArkTS 前端如何通过ApiClient和BackendService对接 Express MongoDB 后端为什么要把 HTTP 细节收敛到ApiClientBackendService如何表达业务语义Bearer Session 如何加入请求头后端快照如何刷新到MockStore网络错误、401、业务错误如何统一提示开发环境如何配置后端地址前后端联调时如何排查“页面没数据”“请求失败”“状态没刷新”等问题。文章重点是工程闭环页面、状态层、服务层、HTTP 层和后端接口各自负责什么。工程背景与源码定位项目是一个宠物邻里 HarmonyOS App包含宠物档案、社区、寄养、提醒、通知和用户中心。后端使用 Express 提供 API数据访问使用 MongoDB Driver。本文涉及的主要文件文件作用MyApp/entry/src/main/ets/services/ApiClient.etsHTTP 请求封装MyApp/entry/src/main/ets/services/BackendService.ets业务接口语义层MyApp/entry/src/main/ets/common/MockStore.ets本地状态和快照刷新MyApp/entry/src/main/ets/pages/login/LoginPage.ets登录入口MyApp/entry/src/main/ets/pages/pet/PetTab.ets宠物档案读写MyApp/entry/src/main/ets/pages/foster/FosterTab.ets寄养需求、地图和申请MyApp/entry/src/main/ets/pages/notice/NoticeTab.ets通知列表和已读houduan/test/package.json后端依赖和测试脚本项目视觉方向如下本文讨论的联调能力最终服务这些真实页面。环境与验证信息项目值HarmonyOS 工程模型modelVersion: 6.0.2target SDK6.0.2(22)compatible SDK6.0.2(22)后端框架Express~4.16.1数据访问MongoDB Driver^4.17.2Node.jsv24.14.1npm11.11.0后端验证命令cd D:\APP\chong_wu_guan_li\houduan\test npm run check npm run test:integration集成测试覆盖寄养留言、通知、坐标、状态时间线和评价这说明前端联调不是只验证登录而是覆盖核心业务链路。一、为什么需要 ApiClient页面里直接写请求会变成这样httpRequest.request(http://localhost:3000/api/pets,{method:http.RequestMethod.POST,header:{Content-Type:application/json},extraData:JSON.stringify(pet)});短期能跑长期会出现问题每个页面都拼 baseUrl每个接口都重复写 headerToken 处理散落401、500、网络失败处理不一致后端路径变化时要改很多页面测试和 Mock 很难切换。所以项目需要ApiClient统一处理 HTTP 细节。二、推荐分层比较稳的分层如下页面层 只负责展示、输入和触发业务动作 MockStore 管理本地状态、乐观更新、失败回滚、版本刷新 BackendService 表达业务接口语义如 createPet、loadSnapshot ApiClient 处理 baseUrl、header、Token、JSON、错误 Express 后端 校验权限、读写 MongoDB、返回统一响应这样页面不需要知道 HTTP 细节后端路径变化也不会影响大面积页面代码。三、ApiClient 基础结构ApiClient可以封装基础请求classApiClient{privatestaticbaseUrl:stringhttp://127.0.0.1:3000/api;privatestaticsessionToken:string;staticsetSessionToken(token:string):void{ApiClient.sessionTokentoken;}staticasyncgetT(path:string):PromiseT{returnApiClient.requestT(GET,path);}staticasyncpostT(path:string,body:object):PromiseT{returnApiClient.requestT(POST,path,body);}}核心在requestprivatestaticasyncrequestT(method:string,path:string,body?:object):PromiseT{consturl${ApiClient.baseUrl}${path};constheaders:Recordstring,string{Content-Type:application/json};if(ApiClient.sessionToken.length0){headers.AuthorizationBearer${ApiClient.sessionToken};}returnApiClient.sendT(url,method,headers,body);}真实项目中send可以基于 HarmonyOS 网络请求 API 实现。四、BackendService 表达业务语义页面不应该调用ApiClient.post(/foster/applications/accept,payload);而是调用BackendService.acceptFosterApplication(application.id);BackendService内部再映射路径staticasyncacceptFosterApplication(id:string):Promisevoid{awaitApiClient.postvoid(/foster/applications/${id}/accept,{});}这样页面读起来就是业务动作而不是接口路径。五、登录和 Bearer Session登录成功后后端返回 session token{userId:u_me,token:session_xxx}前端保存当前用户并设置 tokenAppStorage.setOrCreatestring(AppKeys.CURRENT_USER,result.userId);ApiClient.setSessionToken(result.token);后续请求自动带上Authorization: Bearer session_xxx后端所有需要登录的接口都必须校验 token。不要只靠前端页面隐藏按钮。六、快照加载登录后可以加载业务快照staticasyncloadSnapshot(userId:string):PromiseRemoteSnapshot{returnApiClient.getRemoteSnapshot(/snapshot?userId${encodeURIComponent(userId)});}状态层接收快照staticasyncrefreshFromBackend():Promisevoid{constsnapshot:RemoteSnapshotawaitBackendService.loadSnapshot(MockStore.meId);MockStore.hydrate(snapshot);}hydrate把后端数据写入本地statichydrate(snapshot:RemoteSnapshot):void{MockStore.userssnapshot.users;MockStore.petssnapshot.pets;MockStore.postssnapshot.posts;MockStore.fosterRequestssnapshot.fosterRequests;MockStore.noticessnapshot.notices;MockStore.bumpPetsVersion();MockStore.bumpPostsVersion();MockStore.bumpFosterVersion();MockStore.bumpNoticeVersion();}这样多个 Tab 都能从同一份快照刷新。七、写操作的同步策略以新增宠物为例页面提交表单 - MockStore 本地插入宠物 - bumpPetsVersion 刷新页面 - BackendService.createPet - 成功后 refreshFromBackend - 失败后回滚本地宠物代码结构staticasynccreatePet(draft:Pet):PromisePet|null{MockStore.petsMockStore.pets.concat([draft]);MockStore.bumpPetsVersion();try{awaitBackendService.createPet(draft);awaitMockStore.refreshFromBackend();returnMockStore.getPet(draft.id)??draft;}catch(e){MockStore.petsMockStore.pets.filter((pet:Pet)pet.id!draft.id);MockStore.bumpPetsVersion();MockStore.reportSyncFailure(宠物档案保存失败已撤销本次添加,easError);returnnull;}}这个模式能兼顾交互速度和数据一致性。八、统一错误类型ApiClient不应该直接把底层错误抛给页面。可以统一成业务错误classApiErrorextendsError{status:number0;code:string;retryable:booleanfalse;}常见错误错误处理网络失败提示稍后重试401清空登录态回登录页403提示无权限404提示数据不存在或已删除409提示状态冲突500提示服务异常页面不需要关心 HTTP 状态码细节只展示合适文案。九、401 处理会话过期时可以统一处理if(error.status401){AppStorage.setOrCreatestring(AppKeys.CURRENT_USER,);ApiClient.setSessionToken();thrownewApiError(登录已过期请重新登录);}主入口监听CURRENT_USER后会自动回到登录页。这种集中处理比每个页面都写“如果 401 就跳登录”更可靠。十、同步失败提示项目里可以用syncErrorMessage做统一提示staticreportSyncFailure(message:string,error:Error):void{AppStorage.setOrCreatestring(syncErrorMessage,message);}主入口或页面顶部监听StorageLink(syncErrorMessage)syncErrorMessage:string;这样点赞失败、宠物保存失败、通知已读失败都能走同一个提示出口。十一、开发环境 baseUrl开发阶段常见问题是模拟器或真机访问不到本机后端。要区分场景baseUrl本机浏览器测试http://127.0.0.1:3000/api模拟器访问宿主机视模拟器网络配置而定真机局域网访问http://电脑局域网IP:3000/api生产环境HTTPS 域名前端不要把 baseUrl 写死到多个页面。可以集中到ApiClient或构建配置里。十二、后端响应格式建议后端统一响应{ok:true,data:{}}错误响应{ok:false,code:FOSTER_STATUS_CONFLICT,message:当前寄养需求状态已变化}ApiClient解析后如果ok false统一抛出ApiError。十三、状态冲突处理寄养申请、账号注销、删除帖子这类操作可能发生状态冲突。例如用户 A 刚通过申请用户 B 的页面还停留在旧状态。后端可以返回409{ok:false,code:STATUS_CONFLICT,message:需求状态已变化请刷新后重试}前端处理catch(e){awaitMockStore.refreshFromBackend();MockStore.reportSyncFailure(状态已变化已刷新最新数据,easError);}这比继续使用旧页面状态更安全。十四、调试请求是否发出如果页面没数据先按顺序查页面是否调用了MockStore.refreshFromBackend()BackendService方法是否被调用ApiClientbaseUrl 是否正确后端服务是否启动请求是否带了 Bearer Token后端是否返回 401/404/500hydrate是否把数据写入本地数组写入后是否 bump 对应版本号。这个顺序能覆盖大部分联调问题。十五、调试页面不刷新请求成功但页面不刷新通常不是后端问题而是状态刷新问题现象可能原因后端返回有数据页面空白hydrate没写入对应数组数组有数据页面不动没有bumpXxxVersion列表项内容旧ForEachkey 没覆盖变化字段详情页旧数据路由传了完整旧对象红点不变通知版本没刷新前后端联调时不要只盯 NetworkArkTS 状态链路也要一起看。十六、日志建议开发阶段可以在ApiClient打简洁日志[ApiClient] POST /pets 200 42ms [ApiClient] GET /snapshot 200 83ms [ApiClient] POST /foster/applications/a1/accept 409 31ms不要打印密码、Token、手机号、详细地址等敏感信息。日志只保留路径、状态码、耗时和错误码即可。十七、接口验收清单检查项通过标准baseUrl开发、测试、生产可切换Token需要登录的接口自动带 Bearer错误401、403、404、409、500 有统一处理快照登录后能刷新全部业务数据写操作成功刷新快照失败能回滚或提示页面刷新对应版本号会 bump日志有请求耗时和错误码无敏感信息测试后端集成测试覆盖核心链路这张表能帮助联调从“能跑”走向“可维护”。十八、常见坑页面直接拼 URL后端路径变化后到处改。Token 漏传接口一直 401。只刷新当前页面不刷新其他 Tab。后端成功但MockStore没有 hydrate。失败后没有回滚页面显示不存在的数据。baseUrl 写成 localhost真机访问不到。错误提示直接展示后端堆栈。日志打印 Token 或密码。这些坑都可以通过ApiClient BackendService MockStore分层来减少。总结前后端联调的核心不是“请求能不能发出去”而是数据流是否清晰页面触发动作 - MockStore 管理本地状态 - BackendService 表达业务接口 - ApiClient 处理 HTTP 细节 - Express 后端校验和持久化 - 成功刷新快照或失败回滚 - AppStorage 版本号驱动页面刷新对 HarmonyOS/ArkTS 项目来说这套分层足够轻也足够稳定。它能让宠物档案、社区、寄养、通知、账号安全等模块共用同一套联调基础而不是每个页面各写一套请求和错误处理。