不同能力由两条链路分别承载:
fetch 与 XMLHttpRequest 实现,仅作用于页面脚本发起的请求;SSE Mock 额外代理原生 EventSource,并以 ReadableStream 支持 fetch 流式消费,未命中时回落原生实现;fetch 的响应流可按下行带宽精确交付,XHR 则仅能模拟请求前的延迟和上行带宽;改请求体在请求发出前替换或 JSON 深合并请求体;脚本注入亦复用该通道,按页面 URL 命中后注入自定义 JS / CSS
统计的唯一原始数据是命中日志(RuleHit:规则 ID、动作类型、请求 URL、方法、时间、执行结果)。界面上的各种投影都由它派生,不单独维护计数器。
OFF;全局启用时,当前标签页有任意规则生效则点亮一个小圆点。popup 展示按规则去重后的命中规则数,逐规则以图标标记而非数字角标——次数信息仍完整保留在命中日志里,留给后续的请求日志视图。chrome.webRequest。onRuleMatchedDebug 仅未打包扩展可用,getMatchedRules 只有 pull 且受 20 次 / 10 分钟配额与 5 分钟保留窗口限制,都无法驱动实时状态。观测到请求后由 core.findMatchedRules 判定命中——与页面补丁通道完全同一个匹配器。
utils/dnr-match-parity.test.ts 守护两者的语义一致性。storage.session 供 options 与 popup 标出「未被浏览器接受」的规则。utils/page-plan.ts)在决定动作的同时产出命中记录,不做事后推导。
applied 表示动作真的发生了,skipped 表示规则匹配上、但浏览器限制导致本次请求无法应用(不透明响应读不到响应体、同步 XHR 容不下异步处理),此时一律 fail-open 原样放行。两者用判别联合表达,跳过必带原因。skipped 不计入命中;popup 用单独的状态位标出,让「规则匹配了却没生效」有处可看,而不是只在页面控制台留一行 warn。徽标同样不因它点亮——徽标的判据是「日志里有已执行的命中」,而不是「日志非空」,否则会出现徽标说有规则生效、popup 说什么都没生效的矛盾。storage.session 只作防抖镜像。命中是逐请求写入的,若以 storage 为权威,每条命中都要全量序列化整个数组。
tabs.onRemoved 若因崩溃或扩展更新的事件真空期而丢失,镜像里会留下等不到回收的孤儿日志;查询失败时全量恢复,不做回收。storage.session 配额是全局的。超出上限时整份丢弃最久未更新的标签页,而不是跨标签页削减条数——后者会让某个标签页的数字变成静默的半截。活跃度由日志中最后一条命中的时间还原,镜像无需额外字段。main_frame 请求(webRequest.onBeforeRequest)。重置与该请求自身的命中来自同一事件,天然有序,因此不需要统计窗口时间戳或 Document token。
main_frame。拆成两个监听器时「重置先于记录」只能依赖派发顺序,而 webRequest 并未承诺同一扩展内多个观测监听器的先后。requestId 与新导航区分:主文档被重定向时会以同一 requestId 再次触发 onBeforeRequest,此时不重置,否则这次导航自己的重定向命中会被抹掉。document_start 建立一次 MessageChannel,命中记录只通过私有端口传递;bridge 仍按当前生效规则 ID 校验上报内容。记录时间由接收方盖章,不采信上报值——它参与标签页淘汰的活跃度排序,页面报一个远期时间就能把自己的日志钉住、把别的标签页挤出预算。all_frames,因此 iframe(同域与跨域皆然)内部由页面 JS 发起的 fetch / XHR 不经过该通道:Mock、网络限速、改请求体、脚本注入在子框架内一律不生效。命中统计随之也不包含它们——页面补丁的命中是执行的产物,没有执行就没有可记的命中,这里显示为零是如实反映,而非漏记。
document / img / iframe 一类),前者说的是文档层级。open(..., false))一律原样放行,页面补丁规则不生效。该通道的处理全是异步的——读请求体、执行动态函数、发影子请求都要等微任务或事件;而同步 XHR 要求 send 返回时响应已就绪,插进去只会让页面读到空响应。这里刻意选择 fail-open:宁可规则不生效,也不破坏页面。命中过页面补丁规则时会在页面控制台提示一次,并在 popup 中把该规则标为「匹配上但未应用」,便于排查「为什么规则没生效」。DNR 通道的规则不受影响,仍在网络层照常执行responseText 不能替换为自定义 ReadableStream,因此 SSE 动作会被忽略;同一规则内的限速等其他可执行动作仍照常处理。SSE 请通过 fetch 或原生 EventSource 消费。