declarativeNetRequest 网络请求规则式拦截
本教程共 56 篇 · 第 41 篇 · 更新于 2026-08-13 · 约 6 分钟阅读
本节目标:学完你能用 declarativeNetRequest 声明规则来拦截、重定向、放行或修改网络请求,分清静态规则集、动态规则和会话规则三种来源,并知道每个 action 类型该怎么写。
在 MV3 里,如果你要”改请求”——屏蔽广告域名、把某个网址重定向到新地址、给所有图片请求加上自定义请求头——唯一的正路就是 declarativeNetRequest。它的核心思想是:你不再写一段 JS 在请求发出那一刻临时决定怎么办,而是提前声明一条条规则,浏览器自带的高效匹配引擎在请求到达时自行套用。
这套机制有几个关键特征,先建立直觉:
- 规则式、非阻塞:规则下发后由浏览器在底层网络栈里执行,不占用你的服务工作者(Service Worker),也不会拖慢页面。
- 声明在前,执行在后:你的代码只负责”放规则”,真正的拦截发生在浏览器内核,扩展休眠也不影响。
- 权限收敛:默认只能改你有权限访问的站点,规则要显式声明。
41-1 一条规则由什么组成
每条规则是一个 JSON 对象,包含四个必填字段:id、priority、action、condition。
{
"id": 1,
"priority": 1,
"action": { "type": "block" },
"condition": {
"urlFilter": "||example.com",
"resourceTypes": ["main_frame"]
}
}
四个字段的含义:
id:规则编号,整数,同一规则集内必须唯一。动态/会话规则增删时也靠它定位。priority:优先级,整数。多条规则命中同一请求时,数值大的优先;相等时按规则 ID 小的优先。action:命中后要做什么,类型见后文。condition:在什么条件下算命中,比如 URL 匹配、资源类型、发起方域名等。
condition 里最常用的是 urlFilter 和 resourceTypes。urlFilter 支持 ||(域名及子域)、*(通配)、^(分隔符)等简写。resourceTypes 限定资源种类,常见有 main_frame、sub_frame、stylesheet、script、image、font、xmlhttprequest 等。
Tip想拦整个域及其子域,用
||example.com比https://example.com/*更省事。||表示”任意协议、该域名及子域”。
41-2 静态规则集:随扩展打包
最常见的用法是把规则写进一个 JSON 文件,随扩展一起发布。清单里用 declarative_net_request.rule_resources 声明:
{
"manifest_version": 3,
"name": "请求拦截示例",
"version": "1.0.0",
"background": { "service_worker": "background.js" },
"declarative_net_request": {
"rule_resources": [
{
"id": "ruleset_1",
"enabled": true,
"path": "rules_1.json"
}
]
},
"permissions": ["declarativeNetRequest"]
}
rule_resources 是一个数组,每项描述一个规则集:
id:规则集编号,字符串,全局唯一。enabled:是否默认启用。path:规则文件相对扩展根目录的路径。
一个扩展最多可声明 100 个静态规则集,同时最多启用 50 个(Chrome 限制;Chrome 120 之前曾限 50 声明 / 10 启用)。静态规则集适合”写死”的规则,比如你永远要屏蔽的固定域名列表。
rules_1.json 的内容就是规则数组:
[
{
"id": 1,
"priority": 1,
"action": { "type": "block" },
"condition": {
"urlFilter": "||ads.example.com",
"resourceTypes": ["script", "image"]
}
}
]
41-3 action 的几种类型
action.type 决定命中后干什么,常用五种:
block:直接拦截,请求失败。allow:放行,且让该请求不再被其他规则或扩展处理。优先级要高。redirect:重定向到另一个 URL。upgradeScheme:把 http 升级成 https。modifyHeaders:增删改请求头或响应头。
重定向规则写法:
{
"id": 2,
"priority": 1,
"action": {
"type": "redirect",
"redirect": { "url": "https://example.com/new-page" }
},
"condition": {
"urlFilter": "||old.example.com/page",
"resourceTypes": ["main_frame"]
}
}
修改请求头写法(注意需要 declarativeNetRequestWithHostAccess 权限):
{
"id": 3,
"priority": 1,
"action": {
"type": "modifyHeaders",
"requestHeaders": [
{ "header": "X-Client", "operation": "set", "value": "my-ext" }
]
},
"condition": {
"urlFilter": "||api.example.com",
"resourceTypes": ["xmlhttprequest"]
}
}
requestHeaders 里每项有 operation:set(设值)、append(追加)、remove(删除)。响应头对应 responseHeaders。
Note
allow这类放行规则会”短路”掉后续匹配。一般把放行规则的priority设得比拦截规则高,逻辑才不会乱。
41-4 动态规则:运行时增删、持久保存
静态规则集是写死的。如果你的规则要随用户设置变化——比如用户勾选”开启广告拦截”,或者规则来自云端——就得用动态规则。
动态规则通过 chrome.declarativeNetRequest.updateDynamicRules() 增删:
// 添加一条动态规则
await chrome.declarativeNetRequest.updateDynamicRules({
addRules: [
{
id: 101,
priority: 1,
action: { type: 'block' },
condition: {
urlFilter: '||tracker.example.com',
resourceTypes: ['script', 'image']
}
}
],
removeRuleIds: []
});
// 删除某条动态规则
await chrome.declarativeNetRequest.updateDynamicRules({
addRules: [],
removeRuleIds: [101]
});
动态规则持久保存在浏览器里,扩展重启、浏览器重启都还在。读取当前全部动态规则用 getDynamicRules():
const rules = await chrome.declarativeNetRequest.getDynamicRules();
console.log('当前动态规则数:', rules.length);
用动态规则时,清单权限用 declarativeNetRequest 已足够让扩展管理自己的动态规则。
41-5 会话规则:临时、不落盘
会话规则和动态规则用法几乎一样,区别在生命周期:
- 会话规则只在一个浏览器会话内有效,浏览器关闭后清空。
- 它存在内存里,不写入磁盘。
- 适合”临时生效”的场景,不留下持久痕迹。
await chrome.declarativeNetRequest.updateSessionRules({
addRules: [
{
id: 201,
priority: 1,
action: { type: 'block' },
condition: {
urlFilter: '||temp-block.example.com',
resourceTypes: ['main_frame']
}
}
],
removeRuleIds: []
});
什么时候用会话规则?典型是用户点了”本次浏览临时屏蔽某站”,关掉浏览器就自动还原,干净不留痕。读取用 getSessionRules()。
Tip动态规则和会话规则可以共存,互不覆盖。优先级相同时,会话规则默认排在动态规则之前匹配。记不住就给不同来源的规则分配明确
priority。
41-6 运行时开关静态规则集
除了增删规则,你还能在运行时启用或停用已声明的静态规则集:
// 停用一个规则集
await chrome.declarativeNetRequest.updateEnabledRulesets({
disableRulesetIds: ['ruleset_1']
});
// 启用一个规则集
await chrome.declarativeNetRequest.updateEnabledRulesets({
enableRulesetIds: ['ruleset_1']
});
查询当前启用了哪些规则集用 getEnabledRulesets()。这比重建规则轻量,适合做”总开关”。
41-7 权限怎么配
declarativeNetRequest 相关权限有三个档位:
declarativeNetRequest:能声明静态规则集、增删自己的动态/会话规则。大多数场景够用。declarativeNetRequestWithHostAccess:额外允许modifyHeaders修改请求/响应头,且能作用于你有 host 权限的站点。declarativeNetRequestFeedback:订阅onRuleMatchedDebug等调试事件,观察规则命中情况,仅在调试或需要统计时加。
{
"permissions": ["declarativeNetRequest", "declarativeNetRequestFeedback"],
"host_permissions": ["*://*.example.com/*"]
}
注意:动态/会话规则要改的站点,仍需在 host_permissions 里获得对应权限,否则规则不会生效。
41-8 小结
declarativeNetRequest 的骨架:清单里用 declarative_net_request.rule_resources 声明静态规则集 → 规则对象由 id/priority/action/condition 组成 → action.type 决定 block、allow、redirect、upgradeScheme、modifyHeaders → 需要运行时变化时用 updateDynamicRules(持久)或 updateSessionRules(临时)→ 用 updateEnabledRulesets 做总开关 → 按功能选配权限。
记住一句话:在 MV3 里改请求,永远走规则式声明,不写阻塞式逻辑。 浏览器内核替你执行,扩展休眠也照常工作。下一节讲平台级的 runtime API,看看扩展怎么获取自身信息和打开选项页。