Web 拦截写完,页面加载慢了三倍
给内嵌 H5 做离线资源加速,第一反应是用 onInterceptRequest 把图片和 JS 全部拦下来,从本地读。功能确实通了,但 H5 的加载时间从 1.2 秒涨到了 4 秒以上,滑动也变卡了。你把拦截逻辑翻来覆去地看,查表、读文件、返回响应,每一步都“看起来很快”。问题不在单次拦截的耗时,在onInterceptRequest 是逐请求的同步返回链路,页面上几十个小文件同时触发拦截,跨 Web/ArkTS 边界和查表的累计开销被放大了。更隐蔽的是 onInterceptRequest 拿不到 POST Data,如果你的拦截逻辑试图处理表单提交,数据是空的。

拦截不是越多越好,核心资源和边缘资源要分流
onInterceptRequest 适合拦少量、确定性高的资源,比如首屏关键的 JS 和 CSS。图片、字体这类数量多、单文件小的资源,全部走拦截反而会拖慢加载。更稳的策略是“核心资源打进 HSP,非核心资源走拦截”的混合方案:首屏必需的资源随应用包一起发布,加载路径最短;非核心的大图、按需加载的模块走 onInterceptRequest 从本地或缓存读取。
typescript
Web({ src: this.url, controller: this.controller })
.onInterceptRequest((event) => {
const url = event.request.getRequestUrl();
// 只拦核心 JS/CSS,图片放行给内核缓存
if (!/\.(js|css)(\?|$)/.test(url)) {
return null; // 返回 null 表示不拦截,继续走默认网络
}
const local = this.resolveLocalPath(url);
if (!local) { return null; }
const resp = new WebResourceResponse();
resp.setResponseData($rawfile(local));
resp.setResponseMimeType(url.endsWith('.css') ? 'text/css' : 'application/javascript');
return resp;
})
return null 是放行的信号,不是返回空响应。很多人误以为返回一个空的 WebResourceResponse 就是“放行”,实际上那是返回了一个空内容,页面会直接坏掉。

需要 POST Data 或细粒度资源管理,换成 SchemeHandler
onInterceptRequest 的边界很明确:拿不到 POST Data,也不适合做复杂的响应流式处理。如果你的拦截逻辑需要读取表单提交的内容,或者需要在请求结束后做资源清理,必须换成 SchemeHandler。SchemeHandler 包含请求开始和请求结束两个回调,应用在开始回调里告知 Web 内核是否拦截,在结束回调里清理相关资源,不清理就是内存泄漏。
typescript
import { webview } from '@kit.ArkWeb';
this.controller.setWebSchemeHandler('https', this.schemeHandler);
// schemeHandler 的 onRequestStart 返回是否拦截
// onRequestStop 里释放请求相关的临时资源
自定义 scheme 还有一个时序硬约束:如果拦截的是自定义协议,必须在 Web 组件初始化之前把 scheme 注册到内核,初始化之后再注册会直接失败。需要拦第一个请求的场景,可以先用 initializeWebEngine() 提前初始化内核,再设置 SchemeHandler。
Web 拦截的性能问题,先分清“该不该拦”和“用什么拦”。核心资源走包内、边缘资源走缓存、POST Data 和资源清理走 SchemeHandler,三件事分开,加载速度和内存泄漏就不会同时来找你。下一步可以把你 onInterceptRequest 里拦截的 URL 类型统计一下,看看有多少是本来就不该拦的。
更多推荐

所有评论(0)