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

如何用Chrome扩展监听Next.js网站的Fetch请求响应?

如何用Chrome Extension监听Fetch请求并获取响应数据

肯定可以实现,你之前的fetch替换方案没生效,主要是因为注入时机不对、没覆盖到所有执行上下文,或者页面里有提前加载的fetch调用。下面给两种靠谱的解决办法:

方案一:优化Fetch钩子注入(内容脚本方式)

要让你的钩子能抓到所有页面的fetch请求,得解决注入时机和作用域的问题:

  1. 提前注入脚本
    在manifest.json里配置内容脚本时,设置run_at: "document_start",确保脚本在页面其他资源加载前就跑起来,同时加上all_frames: true覆盖所有iframe:
{
  "content_scripts": [
    {
      "matches": ["*://目标域名/*"],
      "js": ["inject-fetch-hook.js"],
      "run_at": "document_start",
      "all_frames": true
    }
  ]
}
  1. 修复钩子的响应体处理
    你原来的代码里,读取response.text()会把响应体消耗掉,虽然重新造了个Response,但如果页面后续要读json格式就会出错。正确的做法是先克隆响应体再读取:
// inject-fetch-hook.js
(function() {
  const originalFetch = window.fetch;
  window.fetch = async function(input, init) {
    const response = await originalFetch(input, init);
    // 克隆响应体,避免原响应被用掉
    const clonedResponse = response.clone();
    
    // 先尝试读JSON,失败就读文本
    try {
      const data = await clonedResponse.json();
      console.log('抓到Fetch响应:', input, data);
      // 可以把数据发给后台脚本
      chrome.runtime.sendMessage({ type: 'FETCH_RESPONSE', url: input, data });
    } catch (e) {
      const text = await clonedResponse.text();
      console.log('抓到非JSON响应:', input, text);
    }
    
    return response;
  };
})();
  1. 突破隔离世界限制
    Chrome的内容脚本是在隔离环境里跑的,直接替换的window.fetch管不到页面自己的脚本(页面脚本在另一个上下文)。这时候得把钩子代码直接注入到页面主上下文:
// inject-fetch-hook.js
function injectHook() {
  const script = document.createElement('script');
  script.textContent = `
    (function() {
      const originalFetch = window.fetch;
      window.fetch = async function(input, init) {
        const response = await originalFetch(input, init);
        const clonedResponse = response.clone();
        
        // 读取响应后通过自定义事件发给内容脚本
        clonedResponse.json().then(data => {
          window.dispatchEvent(new CustomEvent('fetchCaptured', { 
            detail: { url: input, data } 
          }));
        }).catch(e => {
          clonedResponse.text().then(text => {
            window.dispatchEvent(new CustomEvent('fetchCaptured', { 
              detail: { url: input, text } 
            }));
          });
        });
        
        return response;
      };
    })();
  `;
  document.documentElement.appendChild(script);
  script.remove();
}

// 监听页面发来的捕获事件
window.addEventListener('fetchCaptured', (event) => {
  console.log('内容脚本收到数据:', event.detail);
  // 转发给后台脚本
  chrome.runtime.sendMessage({ type: 'FETCH_DATA', payload: event.detail });
});

injectHook();

这么做能确保钩子跑在页面自己的上下文里,所有页面脚本的fetch调用都能被抓到。

方案二:用Chrome WebRequest API(后台脚本方式)

如果只是想监听响应、不需要改请求,可以用Chrome的webRequest API。注意:这个API默认只能拿到响应头,要拿响应体得额外处理:

  1. 先在manifest里加权限
{
  "permissions": ["webRequest", "webRequestBlocking", "*://目标域名/*"],
  "background": {
    "service_worker": "background.js"
  }
}
  1. 后台脚本里监听并获取响应体
// background.js
chrome.webRequest.onResponseStarted.addListener(
  function(details) {
    // 只处理JSON或文本类型的响应
    const isTextOrJson = details.responseHeaders.some(h => 
      h.name.toLowerCase() === 'content-type' && 
      (h.value.includes('application/json') || h.value.includes('text/'))
    );
    if (isTextOrJson) {
      // 重新发起请求拿响应体(注意:会多一次请求,适合无签名的普通请求)
      fetch(details.url, {
        headers: details.requestHeaders,
        credentials: 'include'
      }).then(res => res.json()).then(data => {
        console.log('WebRequest抓到响应:', details.url, data);
      });
    }
  },
  { urls: ["*://目标域名/*"] },
  ["responseHeaders", "requestHeaders"]
);

提醒:这种方式会发起二次请求,如果请求有一次性token或签名,二次请求可能失败。要是不想发二次请求,可以用chrome.debugger API,但配置比较复杂,适合进阶场景。

你的原方案为啥失效?

  • 注入太晚:页面脚本可能在你的钩子生效前就调用了fetch
  • 没覆盖全:没处理iframe或者页面主上下文的隔离问题
  • 响应体处理错了:原代码读text()后返回新Response,页面后续要读json()会因为响应体被消耗而报错,还可能漏抓一些请求

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 21:13:31