要让通过 Blob
生成的 JS 脚本中的 fetch
请求也能被 HTML 页面中已有的 Hook 代码捕获,可以通过以下几种方法实现:
方法 1:重写全局 fetch
(推荐)
在 Blob 脚本执行前,确保全局 fetch
已被替换。由于 Blob 脚本默认继承当前页面的全局对象(包括 window.fetch
),只需在页面主线程中提前劫持原生 fetch
:
// 保存原生 fetch
const nativeFetch = window.fetch;
// 替换全局 fetch
window.fetch = function(...args) {
console.log('Hook fetch:', args);
// 在这里添加你的拦截逻辑
return nativeFetch.apply(this, args);
};
// 生成并运行 Blob 脚本
const blob = new Blob([`
fetch('https://api.example.com').then(response => console.log(response));
`], { type: 'application/javascript' });
const blobUrl = URL.createObjectURL(blob);
const script = document.createElement('script');
script.src = blobUrl;
document.body.appendChild(script);
关键点:
- Blob 脚本共享父页面的全局作用域,因此直接覆盖
window.fetch
即可生效。
方法 2:动态注入 Hook 代码到 Blob
如果无法提前劫持全局对象,可以在生成 Blob 时直接将 Hook 逻辑插入到脚本中:
const hookCode = `
const nativeFetch = window.fetch;
window.fetch = function(...args) {
console.log('Blob fetch hooked:', args);
return nativeFetch.apply(this, args);
};
`;
const userCode = `
fetch('https://api.example.com').then(response => console.log(response));
`;
// 合并 Hook 代码和用户代码
const blob = new Blob([hookCode + userCode], { type: 'application/javascript' });
const blobUrl = URL.createObjectURL(blob);
const script = document.createElement('script');
script.src = blobUrl;
document.body.appendChild(script);
方法3:使用代理拦截动态脚本
通过 MutationObserver
监听 DOM 变化,在 Blob Script加载前强制注入 Hook:
// Hook逻辑
function injectHook() {
const nativeFetch = window.fetch;
window.fetch = function(...args) {
console.log('Proxy fetch hooked:', args);
return nativeFetch.apply(this, args);
};
}
// 监听动态脚本加载
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.addedNodes.length) {
mutation.addedNodes.forEach((node) => {
if (node.tagName === 'SCRIPT' && node.src.startsWith('blob:')) {
injectHook();
}
});
}
});
});
observer.observe(document.body, { childList: true });
// 生成Blob脚本(同方法1)
注意事项
作用域隔离问题
- Blob脚本默认共享父页面的全局对象,但某些框架(如沙箱环境)可能隔离了作用域。此时需通过
postMessage
通信或直接修改沙箱配置。
- Blob脚本默认共享父页面的全局对象,但某些框架(如沙箱环境)可能隔离了作用域。此时需通过
Service Worker拦截
- Service Worker可以拦截所有网络请求,即使来自Blob的请求也会被捕获:
navigator.serviceWorker.register('/sw.js').then(() => { // Service Worker会接管fetch });
- Service Worker可以拦截所有网络请求,即使来自Blob的请求也会被捕获:
CSP限制
- Content Security Policy可能会阻止Blob执行,需检查HTTP头部的CSP规则。
总结
- 优先方案:直接覆盖
window.fetch
(方法1)。
- 复杂场景:组合使用动态注入(方法2)或代理监听(方法3)。
- 终极方案:Service Worker无差别拦截所有请求。
根据实际需求选择最适合的方式即可。
内容由零声教学AI助手提供,问题来源于学员提问