前面 01-04,我们搞定页面生命周期、JS 双向通信、本地 rawfile 资源、DevTools 调试与缓存清理。
现在进入进阶场景:H5 页面发起网络请求,我们想在鸿蒙原生层拦下来。比如替换图片地址、mock 接口返回、拦截非法请求、给 H5 接口统一追加 token。

我最开始以为直接在 H5 里改 axios 就能搞定,但是有个痛点:H5 代码不在我手里,或者是第三方远程页面。这时候就必须用 ArkWeb 原生的请求拦截。
核心误区:不是所有请求都能直接拦截;ArkWeb 有专门的onInterceptRequest回调,只在这里处理资源劫持,别在其他生命周期事件里写网络劫持逻辑。
在这里插入图片描述

核心概念一句话讲清

onInterceptRequest 是 ArkWeb 的资源拦截回调。H5 发起的图片、JS、接口请求,都会经过这个回调。
我们可以选择:放行请求、替换请求地址,或者直接返回自定义的响应数据(mock 数据、替换图片)。

类比:相当于在 H5 和互联网中间加一道网关,所有进出的网络资源,先过原生这一关。

前置条件:HarmonyOS7,DevEco Studio,沿用前面工程。

第一步:基础请求拦截代码

import { ArkWeb, ArkWebController, WebResourceRequest, WebResourceResponse } from '@kit.ArkWeb';
import { http } from '@kit.NetworkKit';

@Entry
@Component
struct WebInterceptDemo {
  controller: ArkWebController = new ArkWebController();

  aboutToAppear() {
    this.controller.javascriptEnabled = true;
    // 注册资源拦截回调
    this.controller.onInterceptRequest = (request: WebResourceRequest): WebResourceResponse | null => {
      const url = request.requestUrl;
      console.info("拦截到请求地址:", url);

      // 场景1:拦截特定图片,替换成自定义图片
      if(url.includes("old-logo.png")){
        return {
          responseData: $rawfile("new-logo.png"),
          mimeType: "image/png"
        }
      }

      // 场景2:拦截接口,直接mock返回JSON,不访问真实后端
      if(url.includes("/api/test")){
        return {
          responseData: `{"code":200,"msg":"mock成功","data":"来自鸿蒙原生mock"}`,
          mimeType: "application/json"
        }
      }

      // 返回null=放行,正常发起网络请求
      return null;
    }
  }

  build() {
    Column() {
      ArkWeb({
        src: "https://xxx你的测试H5页面",
        controller: this.controller
      })
      .width('100%')
      .layoutWeight(1)
    }
  }
}

关键语句拆解:

  1. onInterceptRequest:每次 H5 发起资源请求就触发,返回WebResourceResponse代表劫持;返回null直接放行。
  2. request.requestUrl 获取请求完整地址,用来判断要拦截的资源。
  3. mimeType 必须匹配资源类型,图片填 image/png,接口 json 填 application/json,写错 H5 无法解析。

在这里插入图片描述

第二步:区分请求类型,只拦截接口,不拦截 JS/CSS

很多人写的时候不加判断,拦截全部资源,页面 css、js 都被卡住,页面直接白屏。
可以通过request.isMainFrame、资源后缀做过滤:

this.controller.onInterceptRequest = (request: WebResourceRequest): WebResourceResponse | null => {
  const url = request.requestUrl;
  // 只拦截接口,忽略css、js、png静态资源
  if(url.endsWith(".css") || url.endsWith(".js") || url.endsWith(".png")){
    return null;
  }
  if(url.includes("/api/")){
    // 在这里处理接口劫持逻辑
    return {
      responseData: `{"code":200,"data":"拦截api返回"}`,
      mimeType:"application/json"
    }
  }
  return null;
}

第三步:给 H5 请求统一追加 Token(常用业务场景)

注意:onInterceptRequest不能直接修改请求 header。
如果需要给 H5 的网络请求统一带上鉴权 token,有两种方案:
方案 A:H5 全局 JS 拦截 fetch/axios(适合自己可控的 H5)
方案 B:在拦截回调里,把原 url 替换成后端网关地址,在原生侧重新发起 http 请求,带上 header,再返回结果。

// 伪代码思路,原生重新发起请求,附加header
// 提示:这里是异步逻辑,onInterceptRequest本身不支持await,复杂请求要注意

在这里插入图片描述

高频踩坑清单(重点)

  1. ❌ 在 onInterceptRequest 里面写 await 异步网络请求
    ✅ onInterceptRequest 是同步回调,不能直接 await。复杂网络请求不要放在这里,容易页面卡顿甚至崩溃。
  2. ❌ mimeType 乱写,返回 json 却写 text/html,H5 拿到数据解析失败
    ✅ json:application/json;png 图片:image/png;jpg:image/jpeg;文本:text/plain
  3. ❌ 拦截主页面 html 本身,忘记放行,直接白屏
    ✅ 写过滤条件,主文档请求一般isMainFrame=true,如果不需要劫持页面 html,直接 return null 放行。
  4. ❌ rawfile 本地页面和远程页面拦截规则一致,rawfile 内部资源也会触发 onInterceptRequest
    ✅ rawfile 页面的 rawfile:// 协议资源同样走拦截回调,注意不要误拦截本地静态资源。

在这里插入图片描述

小扩展:判断请求方式 GET/POST

request 对象可以拿到请求 method,区分 GET POST:

const method = request.requestMethod;
console.info("请求方式:", method);

在这里插入图片描述

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐