跨端实现之网络库拦截

工作中有些一些场景要拦截或改写网络库,比如在做跨端基建的时候,移动端同学说:原生拦截不好使,我和你约定一个request 方法吧。你直接用这个 request 方法调用。在你质疑他技术水平 :)的同时,我们可以思考一下这个场景。如果 H5 侧要拦截所有网络请求并用 request,大家怎么做。

业务同学使用的第三方网络库都不一样,axios,fetch,fly,一大堆。但大家观察一下 chrome 的请求类型基础就两个 fetch 和 XHR。那么搞定这两个我们的这个问题就解决了。

基本结构很简单,你让 llm 帮你写即可,我们仅聊聊思路和跨端场景下的边界场景。首先是劫持或是替换 fetch 和 XHR,以 fetch 举例。

js 复制代码
// ez code
const originalFetch = globalThis.fetch
const originalXMLHttpRequest = globalThis.XMLHttpRequest

globalThis.fetch = myFetch 
globalThis.XMLHttpRequest = myXMLHttpRequest

// my fetch

const myFetch = async function (
    input: RequestInfo | URL,
    options: RequestInit = {},
  ): Promise<Response> {
    try {
      // 处理请求参数
      const url = input.toString()
      const method = options?.method || 'GET'
      const headers = {}
      const body = xxx
  

      // customRequest 是移动端给的一个网络请求han'shu
      const response = await customRequest({
        body: JSON.stringify(body),
        url,
        method,
        headers,
        timeout: 10000,
      });

      try {
        response.data = JSON.parse(response.responseText);
      } catch {
        console.error(
          "Failed to parse response as JSON, using raw response text."
        );
        response.data = {};
      }
      const out = {
        ok: response.statusCode >= 200 && response.statusCode < 300,
        status: response.statusCode,
        statusText: `${response.statusCode}` || "",
        headers: new Headers(response.headers || {}),
        json: () => {
          return Promise.resolve(response.data);
        },
        text: () => Promise.resolve(response.responseText || ""),
        blob: () => Promise.reject(new Error("Blob not supported in fly")),
        formData: () =>
          Promise.reject(new Error("FormData not supported in fly")),
        arrayBuffer: () => Promise.resolve(response.data),
        clone: () => ({
          ok: response.statusCode >= 200 && response.statusCode < 300,
          status: response.statusCode,
          statusText: `${response.statusCode}` || "",
          headers: new Headers(response.headers || {}),
          json: () => Promise.resolve(response.data),
          text: () => Promise.resolve(response.responseText || ""),
          blob: () => Promise.reject(new Error("Blob not supported in fly")),
          formData: () =>
            Promise.reject(new Error("FormData not supported in fly")),
          arrayBuffer: () => Promise.resolve(response.data),
        }),
        data: {
          ...response.data,
          json: () => {
            return Promise.resolve(response.data);
          },
        },
        body: new ReadableStream({
          start(controller) {
            // 将响应数据推送到流中
            const data = response.data || response.responseText || "";
            const encoder = new TextEncoder();
            controller.enqueue(
              encoder.encode(
                typeof data === "string" ? data : JSON.stringify(data)
              )
            );
            controller.close();
          },
        }),
        redirected: false,
        type: "",
        bytes: null,
        bodyUsed: false,
        url,
      } as Response;
      return out
    } catch (error) {
      // 创建一个错误响应
    }
}

这一块需要注意 fetch 请求的 body 需要一个 ReadStream 类型。大多数第三方库会使用这个值。如果没有这个值,即使你请求正常也会拿到空对象(如果第三方库的默认是空)。

常见问题

这一块你基本上可以用 vibe coding。但是代码结构非常重要,因为会有一些边界场景,比如 override 代码(运行时代码执行比业务代码慢导致部分网络请求用原生 fetch / XHR)。有几个思路,

方案一:阻塞业务代码

阻塞主流程直到网络库覆盖完成。优点是直截了当,非常粗暴。但问题是

  1. 运行时代码侵入到业务代码里了
  2. 移动端提供的 request 方法可能不可用,因为 H5 和移动端往往通过 bridge 桥接。桥接流程如果存在同步操作。可能移动端在第一时间无法正常承接你的网络请求,但请求已经进去了。

方案二:网络库重发

相对和业务代码解耦,但问题是

  1. 业务代码注定要面临前几次网络请求被重发的问题。如果处理不好,用户可能会看到接口报错

方案三:容器侧注入运行时

相对常用的运行时注入方案,先对逻辑容器注入,运行时对象。

对于 iOS

swift 复制代码
jsContext.executeJavaScript(`globalfetch = xxx`)

等移动端确定后再加载 H5 的代码,建立业务实例。这样可以完全解耦。

相关推荐
kyriewen8 分钟前
豆包和千问同时关了智能体,我用它们搭的 3 个自动化全废了——迁移方案整理
前端·javascript·ai编程
前端一小卒21 分钟前
我用 TypeScript 从零手写了一个 Claude Code,然后发现它的核心只有 30 行
前端·agent
大圣编程2 小时前
Python中continue语句的用法是什么?
开发语言·前端·python
yuhaiqiang2 小时前
随手 vibecoding 的浏览器插件已经 6000 多次下载,聊聊他的产品设计
前端·后端·面试
之歆2 小时前
Vue商品详情与放大镜组件
前端·javascript·vue.js
再吃一根胡萝卜3 小时前
如何把小米 MiMo 接入 CodeBuddy,打造私有 Agent
前端
负责的蛋挞4 小时前
异步HttpModule的实现方式
java·服务器·前端
丹宇码农7 小时前
把 HLS 字幕玩出花:zwPlayer 如何让 M3U8 视频支持全文搜索、翻译与码率自适应
前端·javascript·音视频·hls·视频播放器
2501_943782357 小时前
【共创季稿事节】猜数字游戏:二分法思维与交互式反馈
前端·游戏·microsoft·harmonyos·鸿蒙·鸿蒙系统