You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

浏览器扩展开发:如何拦截网页自身的Fetch请求响应?

浏览器扩展拦截网页Fetch请求响应的实现方法

核心问题原因

你的代码无法拦截网页自身请求,是因为content_scripts运行在隔离的执行环境,它的window对象和网页主世界的window不是同一个。直接在content_scripts里patch window.fetch,只能拦截content_scripts自身发起的请求,网页的请求不受影响。

同时,browser.tabs是后台脚本(Service Worker/Background Script)专属API,content_scripts确实无法直接调用,需要通过扩展的消息机制和后台脚本交互。


可行解决方案

方案1:将拦截代码注入到网页主世界

要拦截网页的Fetch请求,必须把patch代码放到网页的主执行环境(Main World)里,有两种实现方式:

方式A:使用content_scripts的world配置(推荐,Chrome 110+/Firefox 109+)

在manifest.json里配置content_scripts时,指定world: "MAIN",这样脚本会直接运行在网页主环境:

{
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["fetch-interceptor.js"],
      "world": "MAIN"
    }
  ]
}

然后在fetch-interceptor.js里写你的拦截逻辑(已优化翻译):

const isFirefox = navigator.userAgent.toLowerCase().includes('firefox');

// 兼容Chrome和Firefox的主环境注入
const origFetch = window.fetch;
window.fetch = async (...args) => {
  console.log("Fetch被调用,参数:", args);
  let response = await origFetch(...args);
  console.log("已获取原始响应");

  // 克隆响应避免原响应被消耗
  try {
    const responseData = await response.clone().json();
    console.log("拦截到响应数据:", responseData);
    
    // 这里可以修改响应数据,比如替换内容
    // const modifiedData = { ...responseData, extra: "注入的内容" };
    // return new Response(JSON.stringify(modifiedData), {
    //   status: response.status,
    //   statusText: response.statusText,
    //   headers: response.headers
    // });
    
    // 返回原始响应(或修改后的响应)
    return response;
  } catch (err) {
    console.error("解析响应失败:", err);
    return response;
  }
};

方式B:动态创建script标签注入(兼容旧版浏览器)

如果需要支持更低版本的浏览器,可以在content_scripts里动态创建script标签,把代码注入到网页:

// content-script.js(运行在隔离环境)
const script = document.createElement('script');
script.textContent = `
const origFetch = window.fetch;
window.fetch = async (...args) => {
  console.log("Fetch被调用,参数:", args);
  let response = await origFetch(...args);
  console.log("已获取原始响应");

  try {
    const responseData = await response.clone().json();
    console.log("拦截到响应数据:", responseData);
    // 可修改响应后返回,或直接返回原响应
    return response;
  } catch (err) {
    console.error("解析响应失败:", err);
    return response;
  }
};
`;
document.documentElement.appendChild(script);
script.remove(); // 注入后移除标签,避免DOM污染

方案2:使用浏览器的declarativeNetRequest API(无需注入代码)

如果你的需求只是修改响应头、重定向或者简单替换响应内容,可以用浏览器原生的declarativeNetRequest API,它更高效且不需要注入脚本到网页:

  1. 在manifest.json里声明权限:
{
  "permissions": ["declarativeNetRequest"],
  "host_permissions": ["<all_urls>"]
}
  1. 创建规则文件rules.json:
[
  {
    "id": 1,
    "priority": 1,
    "action": {
      "type": "modifyHeaders",
      "responseHeaders": [
        { "header": "X-Custom-Header", "operation": "set", "value": "intercepted-by-extension" }
      ]
    },
    "condition": {
      "urlFilter": "*",
      "resourceTypes": ["xmlhttprequest", "fetch"]
    }
  }
]
  1. 在manifest.json里引入规则:
{
  "declarative_net_request": {
    "rule_resources": [
      {
        "id": "ruleset_1",
        "enabled": true,
        "path": "rules.json"
      }
    ]
  }
}

该API还支持替换响应体、重定向等操作,可根据需求调整规则。


关于browser.tabs的调用问题

content_scripts无法直接调用browser.tabs,需要通过消息通信和后台脚本交互:

  1. 后台脚本(比如background.js)里监听消息:
// background.js
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.action === "getCurrentTab") {
    chrome.tabs.getCurrent((tab) => {
      sendResponse(tab);
    });
    return true; // 表示异步响应
  }
});
  1. 在content_scripts里发送消息:
// content-script.js
chrome.runtime.sendMessage({ action: "getCurrentTab" }, (response) => {
  console.log("当前标签页信息:", response);
});

内容的提问来源于stack exchange,提问作者FMaz008

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 05:23:24