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

如何将外部域名请求与浏览器活动页面关联?

Hey,这个需求我太熟了——刚好之前折腾过类似的请求拦截扩展,直接给你说结论:仅靠Content Script是没法完成的,得和后台脚本(Background Script/Service Worker)配合才行,下面给你拆解得明明白白:

核心原因:Content Script的权限限制

Content Script是运行在当前页面的隔离环境里的,只能访问页面DOM和有限的浏览器API,根本碰不到全局的网络请求监听能力。而你要做的“关联页面与外部请求”,需要能捕获所有页面发起的网络请求,还要拿到请求的发起源(也就是哪个页面触发的请求)——这些能力只有后台脚本才能通过webRequest API实现。

正确实现方案:Content Script + 后台脚本协作

两者分工明确,配合起来就能实现类似NoScript的功能:

1. 后台脚本:负责请求监听与规则处理

这部分是核心,利用浏览器的webRequest API拦截所有请求,通过details.initiator字段拿到发起请求的页面域名,把请求和页面关联存储;同时处理用户的允许/拒绝指令,实现请求拦截或放行。

给你个Manifest V3的示例代码(现在Chrome、FF、Edge、Opera都支持V3):

// background.js(Manifest V3用Service Worker)
chrome.webRequest.onBeforeRequest.addListener(
  (details) => {
    // 跳过无发起源的请求(比如直接输入URL的请求)
    if (!details.initiator) return;

    const initiatorHost = new URL(details.initiator).hostname;
    const targetHost = new URL(details.url).hostname;

    // 只处理跨域名请求
    if (initiatorHost !== targetHost) {
      // 把请求关联到发起页面域名,存在storage中
      chrome.storage.local.get([initiatorHost], (res) => {
        const domainList = res[initiatorHost] || new Set();
        domainList.add(targetHost);
        chrome.storage.local.set({ [initiatorHost]: Array.from(domainList) });
      });
    }

    // 检查是否是被用户拒绝的域名,是的话直接拦截
    chrome.storage.local.get(['blockedRules'], (res) => {
      const blockedRules = res.blockedRules || {};
      if (blockedRules[initiatorHost]?.includes(targetHost)) {
        return { cancel: true };
      }
    });
  },
  { urls: ["<all_urls>"] },
  ["blocking"] // 要拦截请求必须添加这个参数
);

// 监听来自Content Script的消息
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
  switch(msg.action) {
    case 'getRequests':
      // 返回当前页面的外部请求域名列表
      chrome.storage.local.get([msg.host], (res) => {
        sendResponse({ requests: res[msg.host] || [] });
      });
      return true; // 异步响应需要返回true
    case 'allowHost':
      // 移除对应拦截规则
      chrome.storage.local.get(['blockedRules'], (res) => {
        const blockedRules = res.blockedRules || {};
        if (blockedRules[msg.initiator]) {
          blockedRules[msg.initiator] = blockedRules[msg.initiator].filter(h => h !== msg.target);
          chrome.storage.local.set({ blockedRules });
        }
      });
      break;
    case 'blockHost':
      // 添加拦截规则
      chrome.storage.local.get(['blockedRules'], (res) => {
        const blockedRules = res.blockedRules || {};
        if (!blockedRules[msg.initiator]) blockedRules[msg.initiator] = [];
        if (!blockedRules[msg.initiator].includes(msg.target)) {
          blockedRules[msg.initiator].push(msg.target);
          chrome.storage.local.set({ blockedRules });
        }
      });
      break;
  }
});

2. Content Script:负责页面交互与UI展示

Content Script的作用是在当前页面注入悬浮面板,展示该页面发起的所有外部请求域名,并提供允许/拒绝按钮。它需要和后台脚本通信,获取请求数据,同时把用户操作同步给后台。

示例代码:

// content.js
// 获取当前页面的域名
const currentHost = new URL(window.location.href).hostname;

// 向后台请求当前页面的外部请求列表
chrome.runtime.sendMessage({ action: 'getRequests', host: currentHost }, (response) => {
  if (!response.requests.length) return;

  // 创建悬浮面板
  const panel = document.createElement('div');
  panel.style.cssText = `
    position: fixed;
    top: 20px;
    right: 20px;
    background: #fff;
    border: 1px solid #ddd;
    border-radius: 4px;
    padding: 12px;
    max-width: 300px;
    box-shadow: 0 2px 8px rgba(0,0,0,0.1);
    z-index: 9999;
    font-family: sans-serif;
  `;

  const title = document.createElement('h3');
  title.textContent = '外部请求域名';
  title.style.marginTop = '0';
  panel.appendChild(title);

  response.requests.forEach(host => {
    const item = document.createElement('div');
    item.style.display = 'flex';
    item.style.justifyContent = 'space-between';
    item.style.alignItems = 'center';
    item.style.marginTop = '8px';
    item.textContent = host;

    // 允许按钮
    const allowBtn = document.createElement('button');
    allowBtn.textContent = '允许';
    allowBtn.style.cssText = 'padding:4px 8px;border:none;border-radius:2px;background:#4CAF50;color:white;cursor:pointer;';
    allowBtn.onclick = () => {
      chrome.runtime.sendMessage({ action: 'allowHost', initiator: currentHost, target: host });
      item.remove();
    };

    // 拒绝按钮
    const blockBtn = document.createElement('button');
    blockBtn.textContent = '拒绝';
    blockBtn.style.cssText = 'padding:4px 8px;border:none;border-radius:2px;background:#f44336;color:white;cursor:pointer;margin-left:4px;';
    blockBtn.onclick = () => {
      chrome.runtime.sendMessage({ action: 'blockHost', initiator: currentHost, target: host });
      item.remove();
    };

    const btnContainer = document.createElement('div');
    btnContainer.appendChild(allowBtn);
    btnContainer.appendChild(blockBtn);
    item.appendChild(btnContainer);
    panel.appendChild(item);
  });

  document.body.appendChild(panel);
});
关键配置:Manifest.json

需要在配置文件里声明必要的权限,确保扩展能正常工作:

{
  "manifest_version": 3,
  "name": "页面请求域名管理器",
  "version": "1.0",
  "description": "展示页面发起的外部请求域名并支持允许/拒绝",
  "background": {
    "service_worker": "background.js"
  },
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["content.js"]
    }
  ],
  "permissions": ["webRequest", "webRequestBlocking", "storage"],
  "host_permissions": ["<all_urls>"]
}
额外注意事项
  • Manifest版本:优先用V3,V2已经被主流浏览器逐步淘汰,兼容性更差。
  • 边界情况处理:部分请求(比如本地file://协议的请求)没有initiator字段,后台脚本要跳过这类请求避免报错。
  • 性能优化:如果监听所有请求可能影响性能,可以根据需要只监听script、image、stylesheet等常见资源类型。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 06:52:40