HarmonyOS 7 ArkWeb iframe 失败却没有错误页?API 26 要单独开启子框架

HarmonyOS 7 ArkWeb iframe 失败却没有错误页?API 26 要单独开启子框架
有些页面主体已经打开,右侧嵌入的登录面板或文档预览却是一块空白。开发者给 ArkWeb 配了自定义错误页,回调仍没进,于是以为错误页功能坏了。先看失败的是 mainframe(主框架)还是 iframe(子框架):API 26 的 setErrorPageEnabled(true, true) 才把子框架一并纳入错误页处理范围。

API 20 和 API 26 不要混为一谈
华为的 ArkWeb API 20 差异表已经列出 onOverrideErrorPage 回调及单参数 setErrorPageEnabled(enable)。所以“自定义错误页”本身并不是 HarmonyOS 7 才有的能力。2026-09-04 更新的 API 26 差异表新增的是双参数重载 setErrorPageEnabled(enable, includeSubframe) 和 getSubframeErrorPageEnabled()。
这次变化的实用点是:你可以继续只处理主框架失败,也可以明确选择让子框架失败进入同一套错误页回调。includeSubframe=true 不会把 iframe 错误升级成整个网页错误;回调里仍要用 event.request.isMainFrame() 区分来源,再返回不同内容。
案例一:顶层页面加载失败
用受控测试站点准备一个确定会发生网络错误的主页面 URL,让 Web({ src, controller }) 直接加载它。成功开启错误页能力后,回调的 isMainFrame() 应为 true,这时返回一张完整页面级错误页是合理的。若 src 本身加载失败,却只检查 iframe 的 URL,就会把主页面故障误判为“局部内容缺失”。
排查时记录错误码、是否主框架、当前加载阶段;不要把完整用户 URL、令牌或服务端响应体直接写进日志和错误页。网络错误与 HTTP 协议错误也要分开看,具体错误码以实际回调为准,不能只凭页面“白了”推断是 404。
案例二:顶层页面成功,iframe 加载失败
另一个测试页的主 HTML 能正常打开,里面的 <iframe> 指向一个受控的失败地址。只调用单参数 setErrorPageEnabled(true) 时,不能以“主页面有错误页能力”推断子框架也被覆盖。API 26 下改为双参数 setErrorPageEnabled(true, true),在 onOverrideErrorPage 里按 isMainFrame() === false 返回局部提示,让主页面其他区域继续可用。验收要同时看两点:子框架有可理解的失败信息,主页面导航、输入和其他内容没有被整页替换。
如果你并不希望在嵌入区显示错误页,可以保留仅主框架模式,但应有其他显式的失败反馈;不要把 iframe 空白当成“加载完成”。嵌入第三方站点时,还要确认对方允许被嵌入,不能把跨站策略或服务端拒绝都归咎于错误页开关。
最小 ArkTS 接线
以下代码展示 API 26 的关键接线位置。frame-test.html 是你自己准备的受控测试页,内含一个指向可控失败端点的 iframe;它不是系统内置文件。项目还需按实际工程配置 ArkWeb 与网络访问条件。我当前环境尚未完成 API 26 SDK 编译和真机验证,因此不把这段标成“已在真机跑通”。
import { webview } from '@kit.ArkWeb';
@Entry
@Component
struct FrameErrorDemo {
controller: webview.WebviewController = new webview.WebviewController();
build() {
Web({ src: $rawfile('frame-test.html'), controller: this.controller })
.onControllerAttached(() => {
// 第二个参数是 API 26 新增的子框架范围开关。
this.controller.setErrorPageEnabled(true, true);
console.info(`subframeErrorPageEnabled=${this.controller.getSubframeErrorPageEnabled()}`);
})
.onOverrideErrorPage((event) => {
const main = event.request.isMainFrame();
const code = event.error.getErrorCode();
console.info(`errorPage main=${main}, code=${code}`);
// 返回固定、无用户数据的 HTML;不要拼接原始 URL 或错误详情。
return main
? '<!doctype html><html><body><h1>页面暂时无法打开</h1><p>请检查网络后重试。</p></body></html>'
: '<!doctype html><html><body><p>这块内容暂时不可用,请稍后重试。</p></body></html>';
});
}
}
onControllerAttached() 是让控制器与 Web 组件关联后再配置的入口。真实工程需要按当前 API 26 SDK 的签名检查导入、设备支持范围和回调时序。若同时支持旧系统,不能在旧 SDK 工程里直接复制双参数写法并声称已有兼容分支;要分别构建和测试版本对应的代码路径。
不连设备也能先测哪一层
下面的 Node.js 测试只检验“主框架与子框架生成不同的静态提示”这个业务策略。保存为 error-page-policy.mjs,执行 node error-page-policy.mjs;它不证明 ArkWeb 回调一定触发,也不证明 iframe 的失败一定按预期分类。
import assert from 'node:assert/strict';
function chooseErrorPage(isMainFrame) {
return isMainFrame
? '<h1>页面暂时无法打开</h1><p>请检查网络后重试。</p>'
: '<p>这块内容暂时不可用,请稍后重试。</p>';
}
const main = chooseErrorPage(true);
const frame = chooseErrorPage(false);
assert.match(main, /页面暂时无法打开/);
assert.match(frame, /这块内容暂时不可用/);
assert.notEqual(main, frame);
assert.equal(frame.includes('https://'), false);
console.log('4 policy checks passed');
真机回归要做四次:主框架成功/失败各一次、子框架成功/失败各一次。分别记录回调是否触发、isMainFrame()、getSubframeErrorPageEnabled() 的值以及页面实际替换范围。再把 includeSubframe 关掉重测,确认差异确实来自这个开关,而不是测试站点波动。若两组结果相同,先核对 SDK、系统版本、错误页启用时机和受控失败端点,再谈 API 问题。
选择建议:网页全屏失败时给完整错误页;嵌入模块失败时只给局部提示,不要让一个 iframe 事故吞掉本来正常的主页面。这个边界比“统一返回一个错误 HTML”更重要。
更多推荐



所有评论(0)