欢迎光临

Chrome扩展declarativeNetRequest完全指南:MV3时代网络请求拦截与修改实战

Chrome扩展开发 - 代码编辑器

引言:MV3时代网络请求管理的变革

Chrome扩展的 Manifest V3(MV3)自发布以来,最为开发者所关注的变化之一,就是网络请求拦截机制的全面重构。在 Manifest V2 时代,

1
webRequest

API 的阻塞模式(blocking mode)赋予了扩展几乎无限的网络控制能力——拦截、修改、重定向、屏蔽任何请求。然而,这种能力也带来了严重的性能和隐私问题:每一个网络请求都需要经过扩展的 JavaScript 运行环境,导致页面加载延迟增加,同时也使得扩展能够监控用户的全部浏览活动。

MV3 中,Google 推出了

1
declarativeNetRequest

API 作为替代方案。与传统的

1
webRequest

不同,declarativeNetRequest 采用声明式规则(declarative rules),将请求匹配和处理的逻辑下放到浏览器内核层面执行,而非在扩展的 Service Worker 中逐条处理。这意味着:

  • 性能大幅提升:规则匹配在浏览器底层 C++ 引擎中完成,无需经过 JavaScript 事件循环
  • 更加安全:扩展无法动态读取请求内容,限制了数据泄露风险
  • 后台休眠友好:Service Worker 无需保持唤醒状态来处理网络请求
  • 规则数量有限:静态规则 30000 条上限,动态规则 5000 条上限,会话规则 5000 条上限

本文将深入讲解 declarativeNetRequest API 的核心概念、规则结构、动态规则管理、静态规则配置、条件匹配、以及常见实战场景,帮助你掌握 MV3 时代的网络请求管理技术。

一、declarativeNetRequest 核心概念

1.1 规则(Rule)的结构

declarativeNetRequest 中的每一条规则由三个主要部分构成:条件(condition)、操作(action)和优先级(priority)。理解规则结构是使用该 API 的基础。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
  "id": 1,                    // 规则ID,需在当前规则集合中唯一
  "priority": 1,              // 优先级,数字越大越高
  "condition": {
    "urlFilter": "*://*.example.com/*",
    "resourceTypes": ["main_frame", "sub_frame", "script", "image"],
    "requestMethods": ["get", "post"],
    "domainType": "thirdParty",
    "tabIds": [],
    "excludedTabIds": [],
    "domains": [],
    "excludedDomains": [],
    "initiatorDomains": [],
    "excludedInitiatorDomains": [],
    "requestDomains": [],
    "excludedRequestDomains": [],
    "regexFilter": ""
  },
  "action": {
    "type": "block",           // block, redirect, allow, upgradeScheme, modifyHeaders, allowAllRequests
    "redirect": {},            // 重定向目标
    "requestHeaders": [],      // 修改请求头
    "responseHeaders": []      // 修改响应头
  }
}

1.2 规则类型

declarativeNetRequest 支持六种不同的操作类型:

操作类型 说明 使用场景
1
block
完全阻止请求 广告拦截、跟踪器屏蔽、内容过滤
1
redirect
将请求重定向到另一个URL 强制HTTPS、重定向到本地资源、URL重写
1
allow
允许请求通过(覆盖低优先级规则) 白名单机制、例外规则
1
upgradeScheme
将HTTP升级到HTTPS 安全浏览增强
1
modifyHeaders
修改请求或响应头 自定义User-Agent、添加安全头、CORS调整
1
allowAllRequests
允许资源类型的所有请求(仅限main_frame) 为整个页面设置白名单

1.3 规则集合的层级

declarativeNetRequest 的规则分为三个层级:

  • 静态规则集(Static Rulesets):在 manifest.json 中声明的规则 JSON 文件,不可变,最多 30000 条规则
  • 动态规则(Dynamic Rules):通过 API 在运行时添加/删除的规则,存储在浏览器中持久化,最多 5000 条
  • 会话规则(Session Rules):通过 API 在运行时添加的临时规则,浏览器关闭后丢失,最多 5000 条

二、静态规则集的配置与使用

2.1 manifest.json 配置

要使用静态规则集,首先需要在 manifest.json 中声明

1
declarativeNetRequest

权限,并配置规则集文件:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
{
  "manifest_version": 3,
  "name": "网络请求管理器",
  "version": "1.0.0",
  "permissions": [
    "declarativeNetRequest",
    "declarativeNetRequestFeedback",
    "declarativeNetRequestWithHostAccess"
  ],
  "host_permissions": [
    "*://*/*"
  ],
  "declarative_net_request": {
    "rule_resources": [
      {
        "id": "ruleset_1",
        "enabled": true,
        "path": "rules/block_ads.json"
      },
      {
        "id": "ruleset_2",
        "enabled": false,
        "path": "rules/redirect_https.json"
      },
      {
        "id": "ruleset_3",
        "enabled": true,
        "path": "rules/security_headers.json"
      }
    ]
  }
}

2.2 编写规则 JSON 文件

以下是一个广告拦截规则集的示例:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// rules/block_ads.json
[
  {
    "id": 1,
    "priority": 1,
    "condition": {
      "urlFilter": "||doubleclick.net^",
      "resourceTypes": ["script", "image", "sub_frame"]
    },
    "action": {
      "type": "block"
    }
  },
  {
    "id": 2,
    "priority": 1,
    "condition": {
      "urlFilter": "||googleadservices.com^",
      "resourceTypes": ["script", "image", "sub_frame", "xmlhttprequest"]
    },
    "action": {
      "type": "block"
    }
  },
  {
    "id": 3,
    "priority": 1,
    "condition": {
      "urlFilter": "||googlesyndication.com^",
      "resourceTypes": ["script", "image", "sub_frame"]
    },
    "action": {
      "type": "block"
    }
  }
]

注意:上面的

1
urlFilter

使用了类似 uBlock Origin 的过滤语法。双竖线

1
||

表示域名的开头,

1
^

表示分隔符(任何非字母数字字符或行尾)。

2.3 启用/禁用静态规则集

在扩展运行时,可以通过 API 动态启用或禁用静态规则集:


1
2
3
4
5
6
7
8
9
10
// 启用规则集
chrome.declarativeNetRequest.updateEnabledRulesets({
  enableRulesetIds: ["ruleset_2"],
  disableRulesetIds: ["ruleset_1"]
});

// 检查当前启用的规则集
chrome.declarativeNetRequest.getEnabledRulesets((rulesetIds) => {
  console.log("已启用的规则集:", rulesetIds);
});

三、动态规则管理

3.1 添加动态规则

动态规则允许扩展在运行时根据情况添加自定义规则,常用于实现用户自定义的过滤规则:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 添加动态规则
chrome.declarativeNetRequest.updateDynamicRules({
  addRules: [
    {
      "id": 1001,
      "priority": 100,
      "condition": {
        "urlFilter": "||tracker.example.com^",
        "resourceTypes": ["script", "image", "xmlhttprequest"]
      },
      "action": {
        "type": "block"
      }
    },
    {
      "id": 1002,
      "priority": 200,
      "condition": {
        "regexFilter": "^https?://.*\\.analytics\\..*/collect",
        "resourceTypes": ["xmlhttprequest"]
      },
      "action": {
        "type": "block"
      }
    }
  ],
  removeRuleIds: []  // 可选:同时删除旧规则
}, () => {
  if (chrome.runtime.lastError) {
    console.error("添加规则失败:", chrome.runtime.lastError);
  } else {
    console.log("规则添加成功");
  }
});

3.2 获取和删除规则


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 获取所有动态规则
chrome.declarativeNetRequest.getDynamicRules((rules) => {
  console.log("当前动态规则数量:", rules.length);
  rules.forEach(rule => {
    console.log(`规则 #${rule.id}: ${rule.action.type} ${rule.condition.urlFilter || rule.condition.regexFilter}`);
  });
});

// 删除指定的动态规则
chrome.declarativeNetRequest.updateDynamicRules({
  addRules: [],
  removeRuleIds: [1001, 1002]  // 删除ID为1001和1002的规则
});

// 清空所有动态规则
chrome.declarativeNetRequest.getDynamicRules((rules) => {
  const ids = rules.map(r => r.id);
  chrome.declarativeNetRequest.updateDynamicRules({
    addRules: [],
    removeRuleIds: ids
  });
});

3.3 会话规则

会话规则适用于临时性场景,例如用户在当前浏览会话中临时禁用某个网站的拦截:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 为当前标签页临时添加白名单规则(会话级别)
chrome.declarativeNetRequest.updateSessionRules({
  addRules: [
    {
      "id": 9001,
      "priority": 999,  // 高优先级,覆盖其他规则
      "condition": {
        "requestDomains": ["example.com"],
        "resourceTypes": ["main_frame", "sub_frame"]
      },
      "action": {
        "type": "allowAllRequests"
      }
    }
  ],
  removeRuleIds: []
});

// 获取会话规则
chrome.declarativeNetRequest.getSessionRules((rules) => {
  console.log("会话规则:", rules);
});

// 清除所有会话规则
chrome.declarativeNetRequest.getSessionRules((rules) => {
  chrome.declarativeNetRequest.updateSessionRules({
    addRules: [],
    removeRuleIds: rules.map(r => r.id)
  });
});

四、URL过滤语法详解

4.1 urlFilter 模式

1
urlFilter

支持三种匹配模式,语法简洁但功能强大:

模式 示例 匹配说明
前缀匹配
1
||example.com^
匹配以 example.com 开头的域名及其子域名
后缀匹配
1
.js
匹配以 .js 结尾的URL
子串匹配
1
analytics
匹配URL中包含 analytics 的请求
锚定匹配
1
|https://secure.example.com
匹配以指定字符串开头的URL
尾部锚定
1
/report.pdf|
匹配以指定字符串结尾的URL

4.2 regexFilter 正则匹配

对于更复杂的匹配需求,可以使用

1
regexFilter


1
2
3
4
5
6
7
8
9
10
11
{
  "id": 2001,
  "priority": 100,
  "condition": {
    "regexFilter": "^https?://[^/]+\\.(com|cn|org)/tracking/[0-9]+/pixel\\.(gif|png)$",
    "resourceTypes": ["image"]
  },
  "action": {
    "type": "block"
  }
}

使用正则表达式时需要注意:

  • 正则表达式长度限制为 1800 个字符
  • 不支持
    1
    re2

    语法中不支持的某些高级特性(如反向引用)

  • 建议先使用
    1
    isRegexSupported

    方法验证正则是否有效


1
2
3
4
5
6
7
8
9
10
// 验证正则表达式是否被支持
chrome.declarativeNetRequest.isRegexSupported({
  regex: "^https?://[^/]+\\.com/.*"
}, (result) => {
  if (result.isSupported) {
    console.log("正则表达式可用");
  } else {
    console.error("正则表达式不支持:", result.reason);
  }
});

五、请求头修改实战

5.1 修改请求头

declarativeNetRequest 支持通过

1
modifyHeaders

操作修改请求头或响应头,这在很多场景中非常实用:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 自定义 User-Agent
{
  "id": 3001,
  "priority": 100,
  "condition": {
    "urlFilter": "||example.com^",
    "resourceTypes": ["main_frame", "sub_frame", "script", "xmlhttprequest"]
  },
  "action": {
    "type": "modifyHeaders",
    "requestHeaders": [
      {
        "header": "user-agent",
        "operation": "set",
        "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
      }
    ]
  }
}

5.2 移除安全敏感头


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 移除 Referer 头(隐私保护)
{
  "id": 3002,
  "priority": 100,
  "condition": {
    "urlFilter": "||third-party-tracker.com^",
    "domainType": "thirdParty",
    "resourceTypes": ["image", "script", "xmlhttprequest"]
  },
  "action": {
    "type": "modifyHeaders",
    "requestHeaders": [
      {
        "header": "referer",
        "operation": "remove"
      },
      {
        "header": "cookie",
        "operation": "remove"
      }
    ]
  }
}

5.3 修改响应头增强安全性


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 添加安全响应头
{
  "id": 3003,
  "priority": 100,
  "condition": {
    "resourceTypes": ["main_frame", "sub_frame"],
    "urlFilter": "||example.com^"
  },
  "action": {
    "type": "modifyHeaders",
    "responseHeaders": [
      {
        "header": "x-frame-options",
        "operation": "set",
        "value": "DENY"
      },
      {
        "header": "x-content-type-options",
        "operation": "set",
        "value": "nosniff"
      },
      {
        "header": "referrer-policy",
        "operation": "set",
        "value": "strict-origin-when-cross-origin"
      }
    ]
  }
}

六、综合实战案例:构建一个完整的隐私保护扩展

现在让我们将以上知识整合起来,构建一个完整的隐私保护扩展。该扩展将具备以下功能:

  • 屏蔽第三方跟踪器
  • 强制HTTPS连接
  • 移除追踪相关的请求头
  • 提供用户自定义白名单功能

6.1 项目结构


1
2
3
4
5
6
7
8
9
10
11
privacy-guard/
├── manifest.json
├── background.js
├── popup.html
├── popup.js
├── rules/
│   ├── block_trackers.json
│   ├── upgrade_https.json
│   └── remove_headers.json
└── icons/
    └── icon128.png

6.2 规则文件


1
2
3
4
5
6
7
8
9
10
11
// rules/block_trackers.json
[
  {"id": 1, "priority": 1, "condition": {"urlFilter": "||google-analytics.com^", "resourceTypes": ["script", "image", "xmlhttprequest"]}, "action": {"type": "block"}},
  {"id": 2, "priority": 1, "condition": {"urlFilter": "||facebook.net/tr^", "resourceTypes": ["script", "image", "xmlhttprequest"]}, "action": {"type": "block"}},
  {"id": 3, "priority": 1, "condition": {"urlFilter": "||amazon-adsystem.com^", "resourceTypes": ["script", "image", "sub_frame"]}, "action": {"type": "block"}}
]

// rules/remove_headers.json
[
  {"id": 100, "priority": 1, "condition": {"domainType": "thirdParty", "resourceTypes": ["image", "script", "xmlhttprequest"]}, "action": {"type": "modifyHeaders", "requestHeaders": [{"header": "referer", "operation": "remove"}, {"header": "cookie", "operation": "remove"}]}}
]

6.3 background.js 实现


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
// background.js
chrome.runtime.onInstalled.addListener(async () => {
  // 初始化:确保规则集正确加载
  const enabledSets = await chrome.declarativeNetRequest.getEnabledRulesets();
  console.log("已启用规则集:", enabledSets);
});

// 监听来自 popup 的消息
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  switch (message.type) {
    case "addWhitelist":
      addWhitelistRule(message.domain);
      break;
    case "removeWhitelist":
      removeWhitelistRule(message.domain);
      break;
    case "getWhitelist":
      getWhitelistRules().then(sendResponse);
      return true;
    case "addCustomBlock":
      addCustomBlockRule(message.urlPattern, message.resourceTypes);
      break;
    case "getStats":
      getRuleStats().then(sendResponse);
      return true;
  }
});

async function addWhitelistRule(domain) {
  // 查找是否已有该域名的白名单规则
  const rules = await chrome.declarativeNetRequest.getDynamicRules();
  const existingRule = rules.find(r => r.condition?.requestDomains?.[0] === domain);
 
  if (existingRule) {
    return; // 已存在,跳过
  }

  // 生成新ID
  const maxId = rules.length > 0 ? Math.max(...rules.map(r => r.id)) : 10000;
  const newRule = {
    id: maxId + 1,
    priority: 1000,  // 高优先级,确保覆盖其他规则
    condition: {
      requestDomains: [domain],
      resourceTypes: ["main_frame", "sub_frame", "script", "image", "xmlhttprequest"]
    },
    action: {
      type: "allowAllRequests"
    }
  };

  await chrome.declarativeNetRequest.updateDynamicRules({
    addRules: [newRule],
    removeRuleIds: []
  });
}

async function removeWhitelistRule(domain) {
  const rules = await chrome.declarativeNetRequest.getDynamicRules();
  const ruleToRemove = rules.find(r => r.condition?.requestDomains?.[0] === domain);
 
  if (ruleToRemove) {
    await chrome.declarativeNetRequest.updateDynamicRules({
      addRules: [],
      removeRuleIds: [ruleToRemove.id]
    });
  }
}

async function getWhitelistRules() {
  const rules = await chrome.declarativeNetRequest.getDynamicRules();
  return rules
    .filter(r => r.action.type === "allowAllRequests")
    .map(r => r.condition.requestDomains?.[0])
    .filter(Boolean);
}

async function getRuleStats() {
  const [staticRules, dynamicRules, sessionRules] = await Promise.all([
    chrome.declarativeNetRequest.getEnabledRulesets(),
    chrome.declarativeNetRequest.getDynamicRules(),
    chrome.declarativeNetRequest.getSessionRules()
  ]);

  return {
    enabledRulesets: staticRules,
    dynamicRuleCount: dynamicRules.length,
    sessionRuleCount: sessionRules.length
  };
}

6.4 popup.js 用户交互


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// popup.js
document.addEventListener("DOMContentLoaded", async () => {
  // 加载统计信息
  const stats = await chrome.runtime.sendMessage({ type: "getStats" });
  document.getElementById("dynamic-count").textContent = stats.dynamicRuleCount;
  document.getElementById("session-count").textContent = stats.sessionRuleCount;
  document.getElementById("rulesets").textContent = stats.enabledRulesets.join(", ");

  // 加载白名单列表
  const whitelist = await chrome.runtime.sendMessage({ type: "getWhitelist" });
  const whitelistEl = document.getElementById("whitelist");
  whitelist.forEach(domain => {
    const item = document.createElement("div");
    item.className = "whitelist-item";
    item.innerHTML = `
      <span>${domain}</span>
      <button class="remove-btn" data-domain="${domain}">移除</button>
    `;
    whitelistEl.appendChild(item);
  });

  // 绑定移除按钮事件
  whitelistEl.addEventListener("click", async (e) => {
    if (e.target.classList.contains("remove-btn")) {
      const domain = e.target.dataset.domain;
      await chrome.runtime.sendMessage({ type: "removeWhitelist", domain });
      e.target.parentElement.remove();
    }
  });
});

// 添加白名单
document.getElementById("add-whitelist").addEventListener("click", async () => {
  const input = document.getElementById("domain-input");
  const domain = input.value.trim();
  if (domain) {
    await chrome.runtime.sendMessage({ type: "addWhitelist", domain });
    input.value = "";
    location.reload(); // 刷新列表
  }
});

七、调试与测试

7.1 获取反馈信息

要调试 declarativeNetRequest 规则是否生效,需要申请

1
declarativeNetRequestFeedback

权限:


1
2
3
4
5
6
7
8
9
// 监听网络请求匹配事件
chrome.declarativeNetRequest.onRuleMatchedDebug.addListener((info) => {
  console.log("规则匹配:", {
    ruleId: info.rule.ruleId,
    rulesetId: info.rule.rulesetId,
    tabId: info.tabId,
    request: info.request
  });
});

7.2 在 Chrome 开发者工具中验证

打开 Chrome 的

1
chrome://extensions

页面,找到你的扩展,点击”Service Worker”链接打开控制台。你可以在控制台中看到规则匹配的日志输出。

同时,在 Network 面板中,被 declarativeNetRequest 阻止的请求会显示状态为

1
(blocked:declarativeNetRequest)

,被重定向的请求则显示

1
307 Internal Redirect

7.3 常见问题排查

问题现象 可能原因 解决方案
规则不生效 权限未正确声明 确保 manifest.json 中声明了

1
declarativeNetRequest

权限和

1
host_permissions
规则ID冲突 动态规则ID与静态规则ID重复 动态规则ID建议从 10000 开始,避免与静态规则冲突
正则表达式无效 使用了不支持的语法 使用

1
isRegexSupported

验证,并避免使用反向引用

规则数量超限 添加的规则超过上限 检查动态规则上限 (5000) 和静态规则上限 (30000)
请求未被拦截 被更高优先级的 allow 规则覆盖 检查是否存在优先级更高的 allow/allowAllRequests 规则
Service Worker 未注册 background.service_worker 路径错误 确认 manifest.json 中的路径相对于扩展根目录正确

八、从 webRequest 迁移的注意事项

如果你正在将现有的 MV2 扩展迁移到 MV3,需要注意以下关键差异:

8.1 功能对比

功能 webRequest (MV2) declarativeNetRequest (MV3)
请求拦截 ✅ 灵活,支持动态修改 ✅ 声明式,性能更好
请求体修改 ✅ 支持 ❌ 不支持
响应体修改 ✅ 支持 ❌ 不支持
动态规则 ✅ 完全灵活 ⚠️ 有限制(5000条上限)
性能 ❌ JavaScript 事件循环瓶颈 ✅ 浏览器原生引擎处理
隐私 ❌ 可读取所有请求内容 ✅ 无法读取请求/响应内容
Service Worker 兼容 ❌ 需要持久化后台页面 ✅ 支持休眠,无需常驻

8.2 迁移策略

对于大多数 ad-blocker 和隐私保护类扩展,建议采用以下迁移策略:

  1. 静态规则优先:将不会频繁变动的规则放在静态规则集中,利用 30000 条上限
  2. 动态规则做补充:用户自定义规则使用动态规则,注意 5000 条上限
  3. 会话规则做临时:临时性白名单或调试规则使用会话规则
  4. 考虑多个规则集:按功能模块拆分规则集,通过 API 开关控制
  5. 优化规则数量:使用通配符和正则合并规则,减少规则总数

总结

declarativeNetRequest API 是 Chrome 扩展 MV3 时代最重要的变革之一。虽然它限制了 webRequest 时代的一些灵活性,但在性能、隐私和安全性方面带来了显著提升。通过本文的学习,你应该已经掌握了:

  • declarativeNetRequest 的核心概念和规则结构
  • 静态规则集的配置和使用方法
  • 动态规则和会话规则的管理技巧
  • URL 过滤语法和正则表达式的使用
  • 请求头和响应头修改的实战应用
  • 构建完整隐私保护扩展的完整流程
  • 从 webRequest 迁移的注意事项和策略

随着 Chrome 逐步淘汰 MV2,掌握 declarativeNetRequest 已经成为 Chrome 扩展开发的必备技能。建议你在实际项目中多加练习,逐步将现有的 webRequest 代码迁移到声明式规则体系,以充分利用 MV3 带来的性能优势。

如果你在开发过程中遇到任何问题,可以参考 Chrome 官方文档 或使用

1
chrome://extensions

的检查视图功能进行调试。

【本站文章皆为原创,未经允许不得转载】:汤不热吧 » Chrome扩展declarativeNetRequest完全指南:MV3时代网络请求拦截与修改实战
分享到: 更多 (0)