场景背景
在鸿蒙系统的 H5 混合开发中,我们常使用 Web 组件加载本地离线资源。由于 ArkWeb 内核的安全策略限制,当 Web 内部发起网络请求访问 file 或 resource 协议的资源时,若涉及跨域访问,会被直接拦截。虽然通常建议后端处理 CORS,但鸿蒙官方提供了客户端层面的解决方案。
原因分析
ArkWeb 内核为了提高安全性,默认不允许 file 协议或 resource 协议访问 URL 上下文中来自跨域的请求。这意味着直接使用 resource:// 加载本地 HTML 后,JS 发起的 AJAX 请求若指向其他路径,会触发安全拦截。开发者可以在 DevTools 控制台中看到相关报错信息。
官方方案概述
华为官方文档提供了两种主要解决思路:
- 协议替换:将 file/resource 协议替换为 http/https 自定义域名,配合
onInterceptRequest拦截并替换本地资源。这种方式需要搭建简易服务,配置相对复杂。 - 路径白名单:通过设置允许跨域访问的路径列表,使 file 协议能访问指定目录下的资源。这是更轻量级的方案,适合纯本地资源场景。
实战步骤与坑点
在实际项目中,我采用了第二种方案(路径白名单),以下是具体的落地细节和需要注意的地方。
1. 目录结构调整
项目创建时,系统不会自动生成 resfile 文件夹。我们需要手动在 src/main/resources 下新建该目录,并将打包好的 H5 文件(dist 目录)放入其中。
确保目录结构如下:
src/main/resources/
└── rawfile/
└── resfile/
└── dist/
└── index.html
2. 初始化 Web 组件
加载页面时,初始 src 可以置空,避免立即加载导致后续配置失效。重点在于获取正确的资源路径。
// 构建 Web 组件,src 暂时为空
Web({ src: '', controller: this.webController })
.onControllerAttached(() => {
try {
// 关键步骤:设置允许跨域访问的路径列表
// 必须使用 getContext().resourceDir 拼接实际路径
const basePath = getContext().resourceDir + '/dist/index.html';
this.webController.setPathAllowingUniversalAccess([basePath]);
// 配置完成后,再加载具体页面
..();
} (error) {
.();
}
})
.()
.()
.();


