HarmonyOS ArkWeb 系列之请求拦截与自定义响应:onInterceptRequest 完整指南
文章目录大白话讲清楚拦截请求是什么意思与 onLoadIntercept / onOverrideUrlLoading 的区别流程图核心 API 一览WebResourceRequest请求信息WebResourceResponse构造自定义响应完整示例本地离线包拦截示例2拦截并返回动态 HTML 字符串示例3结合 onLoadIntercept 阻断特定域名注意事项常见 MIME 类型速查小结网页加载时会发出大量网络请求——图片、CSS、JS、API 接口……如果你想把某个请求劫持掉返回自己准备好的数据onInterceptRequest就是那把钥匙。大白话讲清楚拦截请求是什么意思想象一下Web 组件加载网页网页向服务器发了一个 HTTP 请求。正常情况下系统帮你发出去、等响应、渲染页面。onInterceptRequest让你在请求出门之前截住它你想让它继续走正常流程返回null你想用自己的数据替换响应构造一个WebResourceResponse对象返回这有什么用典型场景把线上资源替换成本地缓存离线包方案Mock API 数据方便调试拦截某些广告/追踪请求返回空数据在加载本地 HTML 时把fetch(/api/xxx)的请求重定向到 App 内部逻辑与 onLoadIntercept / onOverrideUrlLoading 的区别很多人容易把这三个回调搞混简单对比一下回调触发时机能否修改响应体典型用途onLoadIntercept主框架导航前不能只能拦截/放行阻止某个 URL 加载onOverrideUrlLoadingURL 被重新加载前不能捕获自定义协议跳转onInterceptRequest任意资源请求含主框架/子资源能替换响应内容、离线包流程图核心 API 一览WebResourceRequest请求信息event.request.getRequestUrl()// 请求的 URLevent.request.isMainFrame()// 是否是主框架请求event.request.isRedirect()// 是否是重定向event.request.isRequestGesture()// 是否由用户手势触发event.request.getRequestHeader()// 请求头列表event.request.getRequestMethod()// 请求方法 GET/POST...WebResourceResponse构造自定义响应constresponsenewWebResourceResponse();// 必须设置的四项response.setResponseData(htmlString);// 响应体string | ArrayBuffer | Resourceresponse.setResponseMimeType(text/html);// MIME 类型response.setResponseEncoding(utf-8);// 编码response.setResponseCode(200);// HTTP 状态码response.setReasonMessage(OK);// 状态说明// 可选自定义响应头constheaders:Header[][{headerKey:Cache-Control,headerValue:no-cache},{headerKey:Connection,headerValue:keep-alive}];response.setResponseHeader(headers);完整示例本地离线包拦截这是最常见的生产级用法——把线上的/static/资源替换成本地 rawfile 中的文件做到即使断网也能用。import{webview}fromkit.ArkWeb;import{BusinessError}fromkit.BasicServicesKit;import{resourceManager}fromkit.LocalizationKit;EntryComponentstruct OfflineCachePage{controller:webview.WebviewControllernewwebview.WebviewController();// 从 rawfile 读取文件内容同步适合小文件privatereadRawFile(path:string):ArrayBuffer|null{try{// getContext().resourceManager 获取资源管理器constrmgetContext(this).resourceManager;returnrm.getRawFileContentSync(path).bufferasArrayBuffer;}catch(e){console.error(readRawFile error:,(easBusinessError).message);returnnull;}}build(){Column(){Web({src:https://example.com,controller:this.controller}).onInterceptRequest((event){if(!event)returnnull;consturlevent.request.getRequestUrl();console.info([Intercept] url:,url);// 只拦截 /static/ 路径下的资源if(url.includes(/static/)){// 把 URL 映射到本地 rawfile 路径// 例如 https://example.com/static/js/app.js → rawfile/static/js/app.jsconstlocalPathurl.replace(https://example.com/,);constdatathis.readRawFile(localPath);if(data){constresponsenewWebResourceResponse();response.setResponseData(data);response.setResponseCode(200);response.setReasonMessage(OK);// 根据文件后缀设置 mimeTypeif(url.endsWith(.js)){response.setResponseMimeType(application/javascript);}elseif(url.endsWith(.css)){response.setResponseMimeType(text/css);}elseif(url.endsWith(.png)||url.endsWith(.jpg)){response.setResponseMimeType(image/png);}else{response.setResponseMimeType(application/octet-stream);}response.setResponseEncoding(utf-8);returnresponse;// 返回自定义响应不走网络}}returnnull;// 其他请求走正常网络}).onPageEnd((event){if(event)console.info(页面加载完成:,event.url);})}.width(100%).height(100%)}}示例2拦截并返回动态 HTML 字符串有时候你想给某个特定 URL 返回一段自己生成的 HTML比如嵌入一个本地配置页import{webview}fromkit.ArkWeb;EntryComponentstruct MockApiPage{controller:webview.WebviewControllernewwebview.WebviewController();// 模拟的 API 返回数据privatemockUserData:stringJSON.stringify({name:张三,age:25});build(){Column(){Web({src:https://myapp.com/home,controller:this.controller}).onInterceptRequest((event){if(!event)returnnull;consturlevent.request.getRequestUrl();// 拦截 /api/user 接口返回 Mock 数据if(url.endsWith(/api/user)){constresponsenewWebResourceResponse();response.setResponseData(this.mockUserData);response.setResponseMimeType(application/json);response.setResponseEncoding(utf-8);response.setResponseCode(200);response.setReasonMessage(OK);// 设置 CORS 头允许跨域constheaders:Header[][{headerKey:Access-Control-Allow-Origin,headerValue:*},{headerKey:Content-Type,headerValue:application/json}];response.setResponseHeader(headers);returnresponse;}returnnull;})}.width(100%).height(100%)}}示例3结合 onLoadIntercept 阻断特定域名onInterceptRequest负责修改响应onLoadIntercept负责完全阻断。两者配合使用效果更好import{webview}fromkit.ArkWeb;EntryComponentstruct BlockAndReplacePage{controller:webview.WebviewControllernewwebview.WebviewController();// 需要屏蔽的追踪域名列表privateblockedDomains:string[][tracker.example.com,ads.doubleclick.net,];privateisBlocked(url:string):boolean{returnthis.blockedDomains.some(domainurl.includes(domain));}build(){Column(){Web({src:https://example.com,controller:this.controller})// 主框架导航拦截.onLoadIntercept((event){if(eventthis.isBlocked(event.data.getRequestUrl())){console.info(主框架导航被阻断:,event.data.getRequestUrl());returntrue;// true 阻止加载}returnfalse;})// 子资源请求拦截图片、脚本等.onInterceptRequest((event){if(!event)returnnull;consturlevent.request.getRequestUrl();if(this.isBlocked(url)){// 返回空响应等于屏蔽了这个请求constresponsenewWebResourceResponse();response.setResponseData();response.setResponseMimeType(text/plain);response.setResponseEncoding(utf-8);response.setResponseCode(200);response.setReasonMessage(OK);returnresponse;}returnnull;})}.width(100%).height(100%)}}注意事项不要在回调中做耗时操作onInterceptRequest是同步回调如果你在里面读大文件或做网络请求会阻塞页面渲染。大文件建议提前加载到内存或者使用异步ResponseDataID方案。mimeType 必须准确如果你返回 JS 文件但 mimeType 写成text/plain浏览器会拒绝执行。二进制文件用 ArrayBuffer图片、字体等二进制资源setResponseData接受ArrayBuffer别用字符串。返回 null 表示不拦截千万别手误返回undefined只有显式返回null才会走正常网络。常见 MIME 类型速查文件类型mimeTypeHTMLtext/htmlJavaScriptapplication/javascriptCSStext/cssJSONapplication/jsonPNG 图片image/pngJPEG 图片image/jpegSVGimage/svgxml字体 woff2font/woff2小结onInterceptRequest是 ArkWeb 中最强大的请求控制手段核心逻辑就两句话返回WebResourceResponse→ 用你的数据跳过网络返回null→ 正常走网络不干预配合onLoadIntercept阻止导航和onOverrideUrlLoading捕获自定义协议你可以对 Web 组件的网络行为做到精细的完全掌控。