ArkTS + HarmonyOS 三方网络库:依赖升级与兼容评审(连载04/04)【共创稿事节】
如果一项依赖的版本升级只需要改动 oh-package.json5 中的一行数字,为什么工程负责人还会坚持安排代码评审和回归检查?因为“依赖已经安装”与“线上契约仍然稳定”是两回事。三方库可以只修改内部实现,也可以调整错误对象、请求超时语义、类型声明甚至依赖树;页面看起来还能显示目录,并不足以证明异常、取消和重试路径没有变化。升级真正要保住的,是用户曾经依赖的行为。

这个系列已经走完三段建设:第一篇将 @ohos/axios 隔离在 KnowledgeHttp,由 KnowledgeService 向页面提供 KnowledgeItem[];第二篇加入四秒单次超时、最多三次只读请求尝试和 requestSerial 旧结果保护;第三篇让传输错误、数据格式错误进入 RequestFailure,通过 CatalogLog 留下安全的诊断线索。收官不重写业务组件,而是把升级变成可审议、可验证、可撤回的工程变更。
依赖升级为什么会牵动四层代码
最常见的误判是“主版本没变,应该没问题”。语义化版本限定的是包发布者声明的兼容承诺,不能替代工程运行验收。^ 允许在一定范围内选择较新的匹配版本,~ 的范围更窄;实际会装到哪个版本,还受源仓库、可用版本、依赖关系与锁定文件影响。尤其三方网络适配器不仅有 JavaScript API,还依赖 HarmonyOS 的运行环境和系统网络能力,升级时应该同时核对目标 SDK、ohpm、ArkTS 类型检查及真实服务端协议。
对这套目录服务,我会把影响面拆为四层。安装层关注能否解析依赖、是否带来新的间接包;适配层关注 axios.create()、get()、响应对象和拦截器;业务层关注 mapKnowledgeItems() 是否继续拒绝非法 items;交互层关注失败提示、重复点击及页面切换后过期回调是否仍被隔离。四层的负责人和证据并不相同,不能用一个“页面加载正常”替它们共同签字。

官方的 ohpm list 可以列出已安装包和其依赖关系;ohpm update 按版本范围更新依赖,并不是一条不经评审的万能修复命令。建议在独立分支先保留升级前的 oh-package.json5 与 oh-package-lock.json5,必要时核对多模块各自的依赖声明。不要为了“清理干净”随意执行会移除锁定文件的操作,否则前后两次对比的基础就丢了。
# 在对应工程/模块路径执行,确认当前安装状态
ohpm list --depth 1
# 针对已确认的依赖进行升级,版本是否改变以实际解析结果为准
ohpm update @ohos/axios
# 再次检查并比较声明文件、锁定文件和依赖树
ohpm list --depth 1
# 版本控制中查看本次变动,不把本地缓存当作交付物
git diff -- oh-package.json5 oh-package-lock.json5 entry/oh-package.json5 entry/oh-package-lock.json5
命令中的包名是已公开的 @ohos/axios,不是假设存在的新库;这里也不预设最新版本号。只有确认包仓中存在相应版本,并在工程配置允许的范围内,才讨论升级。升级前需要记录依赖来源、许可协议、维护情况、重要变更说明与回退点。依赖清单还应覆盖传递依赖,不能只看顶层一个名字。
让业务契约与三方类型保持松耦合
前面的文章定义了 { items: [{ id, title, category }] } 响应以及 KnowledgeItem 的稳定字段。升级最值得检验的正是这些边界,而不是在页面中访问新增加的 Axios 属性。可进一步为适配器抽象一个接口:无论当前或候选版本如何实现,业务服务只接收同一种协议对象。
// network/CatalogGateway.ets
export interface KnowledgeItemDto {
id: string;
title: string;
category: string;
}
export interface KnowledgeListResponse {
items: KnowledgeItemDto[];
}
export interface CatalogGateway {
fetchCatalog(): Promise<KnowledgeListResponse>;
}
KnowledgeHttp 实现上述接口,仍可在内部使用已验证的 axios 实例。业务层则通过构造注入接收该端口,避免编译期依赖传播。为了展示如何升级服务实现,保留下面的最小业务转换逻辑;在已有工程中,应把方法体中的格式校验替换为原先的 mapKnowledgeItems(),确保一致的异常语义。
// service/KnowledgeService.ets
import { CatalogGateway, KnowledgeListResponse,
KnowledgeItemDto } from '../network/CatalogGateway';
export class KnowledgeService {
constructor(private readonly gateway: CatalogGateway) {}
async loadList(): Promise<KnowledgeItemDto[]> {
const raw: KnowledgeListResponse = await this.gateway.fetchCatalog();
if (!Array.isArray(raw.items)) {
throw new Error('DATA_FORMAT');
}
return raw.items.map((item: KnowledgeItemDto): KnowledgeItemDto => {
if (typeof item.id !== 'string' || item.id.length === 0 ||
typeof item.title !== 'string' ||
typeof item.category !== 'string') {
throw new Error('DATA_FORMAT');
}
return { id: item.id, title: item.title, category: item.category };
});
}
}
这里展示的是最小契约端口,实务中应继续复用前篇的 mapKnowledgeItems() 和 RequestFailure,而不是并行维护第二套不同的错误字典。上面为说明边界采用直接抛错,合并进原工程时应统一包装为 RequestFailure('schema', 'DATA_FORMAT', false)。接入升级后的 KnowledgeHttp,只要遵守同一 CatalogGateway,多数页面代码就不需要跟着改动。这样的接口并不能自动解决网络兼容,却让变更的观察点从“整个工程”收缩为“可测试的网络边界”。
测试数据也不该只放正常样本。一个字段缺失、items 为对象、重复 id、服务器返回 401 或 503、请求超时、用户连续两次点击刷新、页面退出后旧请求才结束,都应该列成明确路径。对重复 ID 是否拒绝或者去重,要由现有业务约定决定,不应因为升级依赖而悄然改变。
回归矩阵:把检查写成可验证的事实
回归可以先用一个与 HarmonyOS 运行环境无关的轻量伪网关检查接口契约,确保“合法目录能够转成业务对象、非法目录会被拒绝”这两个基础性质不受三方网络库影响。如下为可在测试模块复用的纯 TypeScript 逻辑,两个测试样本通过同一个入口执行,不依赖真实服务器响应。它不是网络性能测试,而是最小协议回归。
// tests/CatalogContract.ts
import { CatalogGateway, KnowledgeListResponse } from '../network/CatalogGateway';
import { KnowledgeService } from '../service/KnowledgeService';
class StubGateway implements CatalogGateway {
constructor(private readonly result: KnowledgeListResponse) {}
async fetchCatalog(): Promise<KnowledgeListResponse> { return this.result; }
}
export async function checkCatalogContract(): Promise<string[]> {
const findings: string[] = [];
const ok: KnowledgeListResponse = {
items: [{ id: 'k-01', title: '布局', category: 'ArkUI' }]
};
const items = await new KnowledgeService(new StubGateway(ok)).loadList();
if (items.length !== 1 || items[0].id !== 'k-01') {
findings.push('合法目录映射异常');
}
const malformed: KnowledgeListResponse = {
items: [{ id: '', title: '缺失标识', category: 'ArkTS' }]
};
try {
await new KnowledgeService(new StubGateway(malformed)).loadList();
findings.push('非法记录未被拒绝');
} catch (_) { /* 预期拒绝非法记录 */ }
return findings;
}

纯契约检查通过后,再使用可控制的 HTTPS 测试服务验证传输层。推荐按照正常 200、结构错误 200、401、503、延迟超过单次超时、连续两次刷新六组路径执行。每组记录测试环境、请求次数、页面最后显示的数据、是否触发旧响应保护和对应 RequestFailure 阶段。对于 GET 的自动重试,保持第二篇限定的幂等、有限次数原则;不能把这个策略无差别复制到会产生副作用的 POST 请求。关于取消行为、错误码结构和拦截器调用顺序,应逐项对照候选包实际文档与工程运行结果。
正式评审时我会让验证人员保存每个场景的输入条件、期望输出和实际结果,发现失败后将其关联到具体依赖差异。这样后续再次升级时,可以复用同一套检查而不必重新依靠人的记忆。尤其涉及异步请求的路径,要区别“旧请求真正被取消”和“旧响应只是没有进入界面状态”:两者看上去相近,资源占用与测试观察点却不同。还应区分接口业务错误和 HTTP 状态错误;如果后端返回 200 但业务字段异常,重复发送同一个请求通常不能修复结构问题。跨设备验证也应记录具体系统版本与连接环境,而不笼统写一个“鸿蒙设备正常”。
改造还有一层经常被忽视的风险:新增依赖可能改变应用打包体积、权限请求或者系统 API 兼容范围。检查 module.json5 中 INTERNET 声明是否仍是确有需要的最小权限,确认第三方包没有要求应用意外新增敏感权限;留意编译器对 API 变化的诊断,不能用强制类型断言来掩盖不兼容。涉及多个模块时,还应在全工程统一检查是否出现两份版本不一致的网络实现。
决策、回退和这组连载留下的边界
是否发布新依赖,应基于证据而不是口号。评审记录至少包括旧版本与候选版本、依赖声明和锁定结果、变更日志差异、类型检查结果、接口回归清单、平台与设备覆盖情况。出现明显回归,先恢复升级前经过版本管理确认的声明文件与锁定文件,再按原工程构建流程重建并验证;单独将 oh-package.json5 的版本号改回去,却保留不匹配的解析产物,并不是可靠回退。
官方参考:添加依赖项、ohpm list、ohpm update、ohpm clean与锁定文件、Axios适配仓库。具体 SDK 支持范围和候选包版本应以项目实际安装与对应版本说明核验。
这四篇连载最终形成了一条能独立评审的工程路线:依赖被封装在网络适配层,数据在模型层完成运行时校验,超时重试被限制在合适的调用范围内,诊断日志保持统一语义,升级与回退依靠锁定结果和回归证据。技术选择会变,页面需要的可信行为却应尽量不变;真正稳定的不是某个库的版本,而是每一层可以说清、可以复验的职责。
更多推荐

所有评论(0)