适用场景:
- 页面部分资源来自线上(CDN / API / 在线 JS),在设备上加载异常。
- 希望利用 Cordova 提供的拦截与缓存能力(Code Cache),但效果不稳定。
- 想搞清楚
onInterceptWebRequest、SetResourceReplace等能力的正确用法与排错方式。本文基于本仓库中
cordova/README.md的高级用法示例,整理一套 在线资源 + 拦截缓存 的排查与实践指南。
1. 在线资源加载的基本路径
对于在线 JS/CSS/图片等资源,加载路径大致如下:
Web(index.html) ArkWeb WebView MainPage Cordova 拦截层 远端服务器 <script src="https://example.com/app.js"> 触发 onInterceptRequest/onInterceptWebRequest 可选: SetResourceReplace/拦截处理 发起真实网络请求 返回资源/错误 响应内容 执行 JS Web(index.html) ArkWeb WebView MainPage Cordova 拦截层 远端服务器
在 Cordova 提供的高级能力中,我们可以:
- 对特定 URL 进行拦截替换:
- 将线上资源替换为沙箱本地文件或
rawfile中的资源。
- 将线上资源替换为沙箱本地文件或
- 对 JS 做预编译(Code Cache),提升多次打开的加载速度。
2. 预编译与资源替换的示例结构
在 cordova/README.md 中给出了一个较完整的示例,这里抽取核心结构辅助理解:
2.1 配置结构(简化示意)
ts
configs: Array<Config> = [
{
url: 'https://www.tongecn.com/example.js',
localPath: 'example.js', // 文件在 rawfile 目录下
options: {
responseHeaders: [
{ headerKey: 'E-Tag', headerValue: 'xxx' },
{ headerKey: 'Last-Modified', headerValue: 'Wed, 21 Mar 2024 10:38:41 GMT' }
]
}
}
];
2.2 预编译逻辑(onControllerAttached 中)
ts
mainPageCycle = new MainPageCycle().setOnControllerAttached((webviewController: webview.WebviewController, parentPage?: object) => {
console.log('exec onControllerAttached');
for (const config of this.configs) {
let content = this.getUIContext().getHostContext()?.resourceManager.getRawFileContentSync(config.localPath);
try {
this.controller.precompileJavaScript(config.url, content, config.options)
.then((errCode: number) => {
console.log('precompile successfully!');
}).catch((errCode: number) => {
console.error('precompile failed.' + errCode);
});
} catch (err) {
console.error('precompile failed!.' + err.code + err.message);
}
}
});
2.3 拦截替换逻辑(onInterceptWebRequest 中)
ts
onInterceptWebRequest(request: WebResourceRequest, webTag: string): ESObject {
let url = request.requestUrl;
if (url === 'https://www.tongecn.com/v1.1.1/temp/test3.js') {
// 替换到本地沙箱路径
SetResourceReplace(webTag, url, 'https://localhost/data/storage/el2/base/files/test.js');
// 或替换到 rawfile 文件
// SetResourceReplace(webTag, url, 'https://www.example.com/test.js');
}
return null; // 交给默认流程继续
}
3. 常见问题一:预编译不生效 / 仍然每次都重新下载
3.1 排查要点
- precompileJavaScript 的 URL 必须与真实请求 URL 完全一致 :
- 大小写、路径、查询参数都要一样。
- content 是否正确读取 :
getRawFileContentSync(localPath)是否能读到非空字节;localPath是否位于正确的 rawfile 目录。
- 错误码与日志 :
precompile failed.日志中的错误码能给出失败原因。
3.2 建议的日志与校验
在预编译前后加入详细日志:
ts
console.log('[Precompile] url=', config.url, ' localPath=', config.localPath, ' size=', content?.length);
- 若
size为 0 或 undefined,说明本地文件路径有问题。 - 若
url与实际页面请求的 JS 地址不一致,预编译也不会命中。
4. 常见问题二:拦截替换后资源仍然请求线上地址
4.1 判断是否命中 onInterceptWebRequest
在回调的开头打印请求 URL:
ts
onInterceptWebRequest(request: WebResourceRequest, webTag: string): ESObject {
console.log('[Intercept] url=', request.requestUrl);
// ... 其余逻辑
}
- 若日志中完全看不到目标 URL:
- 说明该请求可能是通过其它机制发起(如 XHR/fetch),需要结合具体内核文档确认拦截范围。
- 若能看到 URL,但
SetResourceReplace后仍请求线上:- 重点检查替换后的目标 URL 是否可访问、是否符合 Cordova 的内部协议约定。
4.2 资源替换关系图
SetResourceReplace 原始 URL
https://www.tongecn.com/v1.1.1/temp/test3.js 替换 URL
https://localhost/data/storage/el2/base/files/test.js 本地文件内容
提示:
- 对于
https://localhost/...这样的本地沙箱路径,要确保对应文件真实存在且可读。- 在调试时可以先把替换目标设为另一个可访问的线上地址,以验证
SetResourceReplace是否生效。
5. 常见问题三:线上 JS 调试困难,不知道加载的是哪一个版本
当你对线上 JS 频繁迭代时,很容易出现"设备上到底加载了哪个版本"的困惑,尤其结合缓存/预编译后。
5.1 简单版本标识方案
在 JS 文件中加入版本号 LOG:
js
console.log('[App] online script version = 2024-03-21-01');
- 每次发布新版本,更新版本号;
- 在设备上通过 Web console 或自建日志面板查看当前版本号。
5.2 与预编译配置联动
- 将预编译配置的
options.responseHeaders中E-Tag/Last-Modified与版本号/构建时间关联。 - 需要时可手动调整这些标记以控制缓存策略。
6. 端到端排查流程示例
假设你遇到如下问题:
- 为某个在线 JS 做了预编译和资源替换;
- 但设备上仍频繁访问线上地址,且性能没明显提升。
6.1 排查路线
否 是 否 是 否 是 否 是 预编译+替换不生效 Intercept 日志中有目标 URL 吗? 检查 onInterceptWebRequest 是否正确绑定/路径是否匹配 precompile 时使用的 URL 是否完全一致? 修改 precompile 配置与实际请求统一 替换目标 URL 是否可访问? 检查本地文件存在性/沙箱路径 Web console 中版本号/日志是否符合预期? 检查缓存/E-Tag/Last-Modified 配置 评估是否达到预期性能/流量目标
7. 将在线资源问题纳入整体调试体系
结合前几篇文章(工程结构、Web 调试、白屏排查等),你可以把"在线资源 + 拦截缓存"的问题纳入统一的调试体系:
页面异常/白屏 先确认 index.html/css/js 是否 200 无在线资源时是否正常 引入在线资源后开始异常 检查 onInterceptWebRequest/预编译配置 使用版本号与日志验证实际加载脚本
通过这套方法,你可以在 HarmonyOS + Cordova 混合项目中更从容地使用在线资源,同时利用 Cordova 的拦截与缓存特性实现性能优化,而不会被各种"线上/本地版本错乱"问题搞晕。