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

MV3扩展迁移:如何用declarativeNetRequest替代webRequest修改请求头

MV2 迁移 MV3:请求头条件修改适配方案

核心思路

Manifest V3 中推荐使用 chrome.declarativeNetRequest API 替代 MV2 的 webRequest.onBeforeSendHeaders(blocking 模式在 MV3 中限制较多且性能较差)。针对你需要按 tabId 筛选请求、修改特定请求头的需求,核心是通过动态会话规则绑定指定 tab,并配置请求头修改操作。


步骤1:配置 Manifest 权限

确保 manifest.json 中包含必要权限和声明:

{
  "manifest_version": 3,
  "name": "你的扩展名称",
  "version": "1.0",
  "permissions": ["declarativeNetRequest", "tabs"],
  "host_permissions": ["<all_urls>"],
  "background": {
    "service_worker": "background.js"
  }
}
  • declarativeNetRequest:用于创建网络请求规则
  • tabs:用于监听 tab 关闭事件,清理无效规则
  • host_permissions: ["<all_urls>"]:允许修改所有 URL 的请求头

步骤2:实现动态规则逻辑

在 background.js 中编写代码,实现按 tabId 筛选、修改请求头的逻辑:

// 存储当前生效的规则ID,用于后续移除操作
let activeRuleIds = [];

// 生成指定tab的请求头修改规则
function generateTabRules(tabId, userAgent, deviceType) {
  const rules = [];
  let baseRuleId = tabId * 10; // 用tabId生成唯一规则ID,避免冲突

  // 规则1:修改 User-Agent
  rules.push({
    id: baseRuleId++,
    priority: 1,
    action: {
      type: "modifyHeaders",
      requestHeaders: [{
        header: "User-Agent",
        operation: "set",
        value: userAgent
      }]
    },
    condition: {
      tabIds: [tabId],
      urlFilter: "*",
      resourceTypes: ["main_frame", "sub_frame", "stylesheet", "script", "image", "font", "object", "xmlhttprequest", "ping", "csp_report", "media", "websocket", "other"]
    }
  });

  // 针对 android-phone 设备,添加 sec-ch-ua 系列头规则
  if (deviceType === "android-phone") {
    // 规则2:修改 sec-ch-ua
    rules.push({
      id: baseRuleId++,
      priority: 1,
      action: {
        type: "modifyHeaders",
        requestHeaders: [{
          header: "sec-ch-ua",
          operation: "set",
          value: `"Google Chrome";v="117", "Not;A=Brand";v="8", "Chromium";v="117"`
        }]
      },
      condition: {
        tabIds: [tabId],
        urlFilter: "*",
        resourceTypes: ["main_frame", "sub_frame", "stylesheet", "script", "image", "font", "object", "xmlhttprequest", "ping", "csp_report", "media", "websocket", "other"]
      }
    });

    // 规则3:修改 sec-ch-ua-mobile
    rules.push({
      id: baseRuleId++,
      priority: 1,
      action: {
        type: "modifyHeaders",
        requestHeaders: [{
          header: "sec-ch-ua-mobile",
          operation: "set",
          value: "?1"
        }]
      },
      condition: {
        tabIds: [tabId],
        urlFilter: "*",
        resourceTypes: ["main_frame", "sub_frame", "stylesheet", "script", "image", "font", "object", "xmlhttprequest", "ping", "csp_report", "media", "websocket", "other"]
      }
    });

    // 规则4:修改 sec-ch-ua-platform
    rules.push({
      id: baseRuleId++,
      priority: 1,
      action: {
        type: "modifyHeaders",
        requestHeaders: [{
          header: "sec-ch-ua-platform",
          operation: "set",
          value: `"Android"`
        }]
      },
      condition: {
        tabIds: [tabId],
        urlFilter: "*",
        resourceTypes: ["main_frame", "sub_frame", "stylesheet", "script", "image", "font", "object", "xmlhttprequest", "ping", "csp_report", "media", "websocket", "other"]
      }
    });
  }

  return rules;
}

// 为单个tab应用规则
function applyTabRules(tabId) {
  // 假设 edit 是你的全局配置对象,确保在 service worker 中可访问
  const userAgent = edit.userAgent;
  const deviceType = edit.device;

  // 先移除该tab之前的规则(如果存在)
  const oldTabRules = activeRuleIds.filter(id => Math.floor(id / 10) === tabId);
  if (oldTabRules.length > 0) {
    chrome.declarativeNetRequest.updateDynamicRules({ removeRuleIds: oldTabRules });
    activeRuleIds = activeRuleIds.filter(id => !oldTabRules.includes(id));
  }

  // 添加新规则
  const newRules = generateTabRules(tabId, userAgent, deviceType);
  const newRuleIds = newRules.map(r => r.id);
  chrome.declarativeNetRequest.updateDynamicRules({ addRules: newRules });
  activeRuleIds.push(...newRuleIds);
}

// 批量更新目标tab的规则(对应原MV2中的Tabs数组)
function updateAllTargetTabs(targetTabIds) {
  // 清空所有旧规则
  if (activeRuleIds.length > 0) {
    chrome.declarativeNetRequest.updateDynamicRules({ removeRuleIds: activeRuleIds });
    activeRuleIds = [];
  }

  // 为每个目标tab应用规则
  targetTabIds.forEach(tabId => applyTabRules(tabId));
}

// 监听tab关闭事件,自动清理对应规则
chrome.tabs.onRemoved.addListener(tabId => {
  const rulesToRemove = activeRuleIds.filter(id => Math.floor(id / 10) === tabId);
  if (rulesToRemove.length > 0) {
    chrome.declarativeNetRequest.updateDynamicRules({ removeRuleIds: rulesToRemove });
    activeRuleIds = activeRuleIds.filter(id => !rulesToRemove.includes(id));
  }
});

关键说明

  1. tabId 绑定:通过规则的 condition.tabIds 字段直接指定规则生效的tab,替代原MV2中手动判断tabId的逻辑,更高效。
  2. 动态规则管理:使用 updateDynamicRules 动态添加/移除规则,适配tab列表或配置(userAgent、deviceType)的变化。
  3. 规则ID唯一性:用 tabId * 10 作为规则ID的基础,确保每个tab的规则ID不冲突。
  4. 资源类型覆盖:明确指定 resourceTypes 包含所有需要修改请求头的资源类型,避免遗漏子资源请求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 19:24:59