浏览器扩展开发:如何拦截网页自身的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,它更高效且不需要注入脚本到网页:
- 在
manifest.json里声明权限:
{ "permissions": ["declarativeNetRequest"], "host_permissions": ["<all_urls>"] }
- 创建规则文件
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"] } } ]
- 在
manifest.json里引入规则:
{ "declarative_net_request": { "rule_resources": [ { "id": "ruleset_1", "enabled": true, "path": "rules.json" } ] } }
该API还支持替换响应体、重定向等操作,可根据需求调整规则。
关于browser.tabs的调用问题
content_scripts无法直接调用browser.tabs,需要通过消息通信和后台脚本交互:
- 后台脚本(比如
background.js)里监听消息:
// background.js chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { if (request.action === "getCurrentTab") { chrome.tabs.getCurrent((tab) => { sendResponse(tab); }); return true; // 表示异步响应 } });
- 在content_scripts里发送消息:
// content-script.js chrome.runtime.sendMessage({ action: "getCurrentTab" }, (response) => { console.log("当前标签页信息:", response); });
内容的提问来源于stack exchange,提问作者FMaz008
相关产品推荐
相关产品推荐

