首页 / 浏览器扩展开发入门教程 / declarativeNetRequest 网络请求规则式拦截

浏览器扩展开发入门教程

declarativeNetRequest 网络请求规则式拦截

本教程共 56 篇 · 第 41 篇 · 更新于 2026-08-13 · 约 6 分钟阅读

declarativeNetRequest网络请求规则集动态规则会话规则请求拦截Manifest V3

本节目标:学完你能用 declarativeNetRequest 声明规则来拦截、重定向、放行或修改网络请求,分清静态规则集、动态规则和会话规则三种来源,并知道每个 action 类型该怎么写。

在 MV3 里,如果你要”改请求”——屏蔽广告域名、把某个网址重定向到新地址、给所有图片请求加上自定义请求头——唯一的正路就是 declarativeNetRequest。它的核心思想是:你不再写一段 JS 在请求发出那一刻临时决定怎么办,而是提前声明一条条规则,浏览器自带的高效匹配引擎在请求到达时自行套用。

这套机制有几个关键特征,先建立直觉:

  • 规则式、非阻塞:规则下发后由浏览器在底层网络栈里执行,不占用你的服务工作者(Service Worker),也不会拖慢页面。
  • 声明在前,执行在后:你的代码只负责”放规则”,真正的拦截发生在浏览器内核,扩展休眠也不影响。
  • 权限收敛:默认只能改你有权限访问的站点,规则要显式声明。

41-1 一条规则由什么组成

每条规则是一个 JSON 对象,包含四个必填字段:idpriorityactioncondition

{
  "id": 1,
  "priority": 1,
  "action": { "type": "block" },
  "condition": {
    "urlFilter": "||example.com",
    "resourceTypes": ["main_frame"]
  }
}

四个字段的含义:

  • id:规则编号,整数,同一规则集内必须唯一。动态/会话规则增删时也靠它定位。
  • priority:优先级,整数。多条规则命中同一请求时,数值大的优先;相等时按规则 ID 小的优先。
  • action:命中后要做什么,类型见后文。
  • condition:在什么条件下算命中,比如 URL 匹配、资源类型、发起方域名等。

condition 里最常用的是 urlFilterresourceTypesurlFilter 支持 ||(域名及子域)、*(通配)、^(分隔符)等简写。resourceTypes 限定资源种类,常见有 main_framesub_framestylesheetscriptimagefontxmlhttprequest 等。

Tip

想拦整个域及其子域,用 ||example.comhttps://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 里每项有 operationset(设值)、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,看看扩展怎么获取自身信息和打开选项页。