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

如何在Violentmonkey脚本中用Service Worker拦截fetch并缓存音频?

解决方案:用户脚本中拦截Fetch并缓存音频

首先要明确:你用的普通Worker根本无法拦截页面的全局Fetch请求,它只能监听自身内部发起的Fetch,所以你的代码不会触发页面的Fetch事件,只有Service Worker才能实现全局请求拦截。下面提供两种可行方案:


方案一:用Service Worker实现拦截(推荐)

用户脚本中无法直接用相对URL注册Service Worker,核心问题在于脚本沙箱限制,需要访问页面的真实navigator对象,同时用Blob生成Service Worker脚本的URL来注册。

代码示例

// 构造Service Worker的核心逻辑
const swCode = `
self.addEventListener('fetch', (event) => {
  // 匹配音频文件,可根据实际需求修改规则
  const audioExtensions = /\\.(mp3|wav|ogg|flac)$/i;
  if (audioExtensions.test(event.request.url)) {
    event.respondWith(
      caches.match(event.request)
        .then(cachedResponse => {
          // 有缓存直接返回
          if (cachedResponse) {
            console.log('返回缓存音频:', event.request.url);
            return cachedResponse;
          }
          // 无缓存则请求并缓存
          return fetch(event.request)
            .then(networkResponse => {
              caches.open('audio-cache-v1')
                .then(cache => cache.put(event.request, networkResponse.clone()));
              return networkResponse;
            });
        })
    );
  }
});
`;

// 生成Service Worker的Blob URL
const swBlob = new Blob([swCode], { type: 'text/javascript' });
const swUrl = URL.createObjectURL(swBlob);

// 访问页面的真实navigator(Tampermonkey用unsafeWindow,Greasemonkey用GM.window)
const pageNavigator = unsafeWindow.navigator;

// 注册Service Worker,scope设为根目录确保覆盖所有音频请求
pageNavigator.serviceWorker.register(swUrl, { scope: '/' })
  .then(reg => console.log('Service Worker注册成功:', reg.scope))
  .catch(err => console.error('Service Worker注册失败:', err));

注意事项

  • 脚本管理器权限:需开启对目标站点的访问权限(如Tampermonkey中设为"在所有网站上")
  • HTTPS限制:Service Worker仅支持HTTPS环境(localhost除外),HTTP站点无法使用
  • 缓存维护:可添加缓存清理逻辑,比如定期删除旧版本缓存

方案二:重写页面的Fetch函数(无需Service Worker)

如果目标站点是HTTP,或者无法使用Service Worker,可直接劫持页面的全局Fetch函数,在主线程实现缓存逻辑。

代码示例

// 保存原始Fetch函数
const originalFetch = unsafeWindow.fetch;

// 重写全局Fetch
unsafeWindow.fetch = async function(...args) {
  const request = new Request(args[0], args[1]);
  // 匹配音频文件
  const audioExtensions = /\\.(mp3|wav|ogg|flac)$/i;
  if (audioExtensions.test(request.url)) {
    const cacheKey = `audio-cache:${request.url}`;
    // 检查localStorage缓存
    const cachedData = localStorage.getItem(cacheKey);
    if (cachedData) {
      console.log('返回缓存音频:', request.url);
      const blob = await fetch(cachedData).then(res => res.blob());
      return new Response(blob, { headers: request.headers });
    }
    // 发起原始请求并缓存
    const response = await originalFetch(...args);
    const blob = await response.clone().blob();
    const reader = new FileReader();
    reader.onload = () => localStorage.setItem(cacheKey, reader.result);
    reader.readAsDataURL(blob);
    return response;
  }
  // 非音频请求调用原始Fetch
  return originalFetch(...args);
};

优缺点

  • 优点:无需Service Worker,兼容性更好,支持HTTP站点
  • 缺点:缓存存在localStorage,容量有限(约5MB);仅能拦截Fetch请求,XMLHttpRequest需额外处理;主线程处理缓存可能影响页面性能

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 23:10:40