
本文介绍一种可靠方法:通过 content script 动态注入脚本到页面主执行环境(main world),从而真正拦截网页自身发起的 fetch 请求响应,绕过 content script 沙箱限制。
本文介绍一种可靠方法:通过 content script 动态注入脚本到页面主执行环境(main world),从而真正拦截网页自身发起的 fetch 请求响应,绕过 content script 沙箱限制。
在开发浏览器扩展时,若仅在 content_scripts 中重写 window.fetch,实际无法拦截网页自身(即页面主线程、非扩展注入上下文)发起的 fetch 调用——这是因为 Chrome 和 Firefox 的 content script 运行在隔离世界(isolated world),与页面 DOM 和全局对象(如 window.fetch)逻辑分离。你修改的是扩展自己的 fetch 引用,而非网页原始作用域中的 fetch。
✅ 正确解法是:将 monkey patch 代码注入到页面的主执行环境(main world),使其直接覆盖网页自身的 window.fetch。这需借助 chrome.runtime.getURL() 加载外部 JS 文件,并通过动态 <script></script> 标签注入实现。
✅ 实现步骤
-
在
content_scripts中注入主世界脚本(例如放入content.js):// content.js —— 运行在 isolated world,仅负责注入 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', injectMainWorldScript); } else { injectMainWorldScript(); }
function injectMainWorldScript() { const script = document.createElement('script'); script.src = chrome.runtime.getURL('scripts/attach.js'); script.onload = () => script.remove(); (document.head || document.documentElement).appendChild(script); }
2. **创建 `scripts/attach.js`(关键补丁文件)**:
该文件将运行在页面主世界,可直接访问并修改 `window.fetch`:
```js
// scripts/attach.js —— 运行在 main world(与网页同上下文)
const originalFetch = window.fetch;
window.fetch = async function(...args) {
try {
const response = await originalFetch(...args);
// ⚠️ 注意:仅对 JSON 响应做克隆解析;二进制内容(图片、PDF等)会失败
if (response.headers.get('content-type')?.includes('application/json')) {
const cloned = response.clone();
let data = null;
try {
data = await cloned.json();
console.log('[Extension] Intercepted JSON response:', data);
// ✅ 在此处修改响应数据(如脱敏、注入字段、模拟错误等)
// data = { ...data, intercepted: true, timestamp: Date.now() };
// 返回修改后的响应
return new Response(JSON.stringify(data), {
status: response.status,
statusText: response.statusText,
headers: response.headers
});
} catch (jsonErr) {
console.warn('[Extension] Failed to parse JSON:', jsonErr);
}
}
// 非 JSON 响应或解析失败 → 原样返回,避免破坏资源加载
return response;
} catch (err) {
console.error('[Extension] Fetch error:', err);
throw err;
}
};
? 关键注意事项
-
必须使用
chrome.runtime.getURL():确保路径正确且受扩展权限保护;不可使用相对路径或fetch()加载。 -
避免污染全局变量:
attach.js中定义的变量(如originalFetch)仅在当前执行上下文有效,不会与网页其他脚本冲突。 -
Content-Type 判断必不可少:
response.clone().json()对非 JSON 响应(如image/png,text/html)会抛出异常,务必前置判断或包裹try/catch。 -
响应头需透传:若返回自定义
Response,建议复制原始status、statusText和headers,否则可能引发 CORS 或状态码异常。 -
Firefox 兼容性:该方案在 Firefox(Manifest V3)和 Chrome 均有效;但注意 Firefox 的
content_scripts.run_at默认为"document_idle",可设为"document_start"提前注入。 - *不要在
attach.js中调用 `chrome.API**:主世界脚本无扩展权限,所有通信需通过window.postMessage+content_scripts` 监听中转(如需上报拦截结果)。
✅ 总结
真正拦截网页自身 fetch 响应的核心在于执行环境的统一。Content script 的沙箱机制是安全特性,而非缺陷;主动注入主世界脚本,既符合浏览器安全模型,又达成功能目标。相比 Service Worker 拦截(仅适用于 extension 自发请求)或 DevTools 协议(需高权限且不稳定),此方案轻量、稳定、跨浏览器兼容,是生产级扩展推荐实践。











