declarativeNetRequest:MV3 的网络请求拦截新姿势

MV2 的 webRequest API 允许扩展同步监听并修改每个网络请求,能力强但等于把整条流量放进扩展手里。MV3 用 declarativeNetRequest 取而代之:扩展不再「看」请求内容,只提交一批声明式规则,由浏览器内核执行拦截与改写。隐私更好、性能更高,写法也完全不同。Chrome 84+ 可用。

规则的基本形状

一条规则由 condition(匹配什么)和 action(做什么)组成:

{
  "id": 1,
  "priority": 1,
  "action": { "type": "block" },
  "condition": {
    "urlFilter": "||ads.example.com/",
    "resourceTypes": ["script", "image"],
    "initiatorDomains": ["mysite.com"]
  }
}

action 类型五种:block(拦截)、redirect(重定向)、upgradeScheme(http 升 https)、allow(放行,抵消其他规则)、modifyHeaders(改请求/响应头)。condition 的核心是 urlFilter,它不是正则而是专用模式语法:|| 锚定域名开头、| 锚定首尾、^ 匹配分隔符、* 通配任意串。想要真·正则用 regexFilter 字段,每种规则类型的正则规则总数上限 1000 条,单条编译后不能超过 2 KB,超了会被忽略并告警。

三种规则集

类型 管理方式 生命周期
静态规则 JSON 文件打进扩展包 随安装/升级更新
动态规则 JS 调 updateDynamicRules 跨会话、跨升级持久
会话规则 JS 调 updateSessionRules 浏览器关闭或扩展升级即清

静态规则在 manifest 里登记:

"declarative_net_request": {
  "rule_resources": [
    { "id": "ruleset_1", "enabled": true, "path": "rules_1.json" }
  ]
},
"permissions": ["declarativeNetRequest"]

容量概念:静态规则集最多 100 个、同时启用最多 50 个,全部启用合计至少保证 30000 条;动态规则至少 5000 条,其中 block/allow/allowAllRequests/upgradeScheme 这类「安全规则」从 Chrome 121 起享有 30000 条的单独额度;会话规则 5000 条。运行时可调 getAvailableStaticRuleCount 查询剩余额度。

动态规则:用户级拦截

广告拦截类扩展的「自定义规则」用动态规则实现:

// 加一条:拦截 example.net 上的追踪脚本
await chrome.declarativeNetRequest.updateDynamicRules({
  addRules: [{
    id: 9001,
    priority: 1,
    action: { type: "block" },
    condition: { urlFilter: "||example.net/tracker", resourceTypes: ["script"] }
  }],
  removeRuleIds: [9001]
});

注意 removeRuleIds 先行清掉同 id 旧规则的写法,这是更新规则的标准姿势(add 与 remove 在同一次调用里,remove 先执行)。改请求头则用 modifyHeaders:

{
  "id": 9002,
  "priority": 1,
  "action": {
    "type": "modifyHeaders",
    "requestHeaders": [
      { "header": "User-Agent", "operation": "set", "value": "MyUA/1.0" }
    ]
  },
  "condition": { "urlFilter": "||api.example.com/", "resourceTypes": ["xmlhttprequest"] }
}

operation 有 set、append、remove 三种,responseHeaders 同理。

两个权限变体怎么选

  • declarativeNetRequest:安装时有权限警告,但隐式获得 block/allow/allowAllRequests 能力,不需要 host_permissions。纯拦截场景选它;
  • declarativeNetRequestWithHostAccess:安装时无警告,但拦截/重定向/改头都需要对应站点的 host 权限。已经有 host 权限的扩展选它,避免叠加警告。

与 webRequest 的取舍

MV3 的 webRequest 仍在,但只剩「观察」能力,阻塞式修改被移除。迁移期判断标准:只拦截、改头、重定向 → declarativeNetRequest;必须读取请求体内容做分析 → 重新设计功能,或改用 debug 协议等重手段。规则优先级与多扩展竞争的细节(同优先级时 allow > block > redirect 等)官方有精确算法,做拦截类产品前务必通读。官方文档:https://developer.chrome.com/docs/extensions/reference/api/declarativeNetRequest

urlFilter 模式与正则的关系密切,语法细节不熟的话见 正则实战;规则文件属静态资源,打包注意事项见 《打包与版本管理》 篇。

调试规则的三板斧

规则「不生效」或「误伤」时,三个手段定位问题:

  1. 静态规则报错看加载日志:未打包扩展的规则文件有语法或字段错误时,chrome://extensions 的错误按钮会精确指出第几条规则、哪个字段;打包扩展的无效规则会被静默忽略——所以开发期始终用未打包方式测试规则;
  2. onRuleMatchedDebug 观察命中:加 declarativeNetRequestFeedback 权限(仅未打包扩展可用)后监听该事件,每条规则命中都会回调,能直接看到「哪条规则、匹配了哪个请求」;
  3. getMatchedRules 查最近命中:同样需要 feedback 权限,返回最近匹配的规则列表,适合做事后分析。
chrome.declarativeNetRequest.onRuleMatchedDebug.addListener((info) => {
  console.log("规则命中", info.rule.ruleId, "->", info.request.url);
});

发布版记得移除 feedback 权限——它只服务调试,留着会触发不必要的权限警告。

规则设计的工程实践

写拦截规则集(尤其量大时)有几条经验值得固化:

  • id 管理集中化:动态规则的 id 用常量或生成器统一分配,散落各处的魔法数字是重复 id 报错的根源;更新规则坚持「removeRuleIds 先行」的写法;
  • 优先级显式声明:官方文档特别提醒,同优先级的执行顺序不做标准化保证,依赖默认顺序的规则组合随时可能变脸,永远显式写 priority;
  • 用 urlFilter 而非滥用 regexFilter:正则规则有 1000 条总量与 2 KB 编译后体积的双重限制,能用地 ||domain^ 模式解决的别上正则;
  • 规则集分文件:按功能拆 rules_social.json、rules_tracker.json,利用 rule_resources 的 enabled 开关做功能分区,也方便未来做「用户选择性启用」。

urlFilter 的模式语法与正则的能力边界,正则功底决定你写规则的效率,见 正则实战。规则文件属于扩展静态资源,打包规范见 《打包与版本管理》 篇。

本章由 WorkBuddy 原创整理,API 行为依据 Chrome 扩展官方文档(Manifest V3)。