调试页面性能的时候,我经常遇到一种特别让人头疼的情况:整站加载没什么大问题,但某个第三方脚本、一个统计上报或者某个特定接口总是拖慢速度、报错,甚至影响渲染。以前这种问题只能靠全局策略去猜,要么改代码,要么在本地开发服务器里做转发拦截,特别绕。直到我确认 Chrome DevTools 终于支持限制单个网络请求,这个问题才真正有了一个轻量、精确的解法。
这篇东西写给两类人看:一类是前端开发,做性能优化或者查线上问题时天天要和 Network 面板打交道;另一类是测试和爬虫工程师,经常需要模拟接口失效、统计上报被阻断的情况。你不需要安装任何第三方扩展,不用改一行代码,只要会用浏览器开发者工具,1分钟就能上手。我尽量把操作细节、背后原理和踩过的坑都整理出来,保证你能直接照着做。
1. 这东西到底解决了什么问题
1.1 以前调试“单个请求”有多麻烦
我最早遇到“只想拦一个请求”的需求,是在排查一个第三方埋点脚本的时候。页面加载总是卡一下,Network 面板里有个请求稳稳地占着长尾,我很想验证一下“没有它,页面是不是就快了”。但当时能用的办法都很笨。
第一种是全局屏蔽域名的扩展方案。装上广告拦截类扩展,把这个第三方域名加进黑名单,结果是整个域名下的所有请求全没了。可那个域名下面还托着另一个接口,我这边只是不想让它上报,并不是想把人家的正常服务也干掉。扩展的粒度实在太粗。
第二种是抓包工具或本地转发方案。把请求拦截到本地再转发出去,听起来可行,但配置复杂,还要处理 HTTPS 证书的问题。而且它影响的往往不是当前一个调试页面,而是整个系统里的所有连接,搞不好就把同事的正常环境给带崩了。要是遇到跨域、预检请求,情况更麻烦。
第三种是直接改代码。临时注释掉埋点调用,重新编译,然后再刷新页面验证。如果是打包项目,这一来一回可能就是几分钟甚至十几分钟。验证完了还得记得把代码改回来,万一忘了提交,事故就大了。而且有些第三方脚本不是你能改源码的,这种方案直接失效。
所以你会发现,过去的调试工具在“请求粒度”上一直有个缺口:要么全留下,要么全挡住,很难针对某一个 URL 做精准控制。网络限速倒是可以模拟整体慢速,但它是作用于整个页面,不是针对某一两个请求。这个缺口导致了大量调试需求只能靠绕路去解决。
1.2 什么场景下最值得用它
我把平时会用到“单个请求屏蔽”的场景整理了一下,大概有这么几类。
第三方依赖排查。页面上有一个脚本是从远端加载的,你怀疑它拖慢了首屏。给它单独加一条屏蔽规则,刷新页面,看请求瀑布流和关键指标的变化,一下子就能判断它到底是不是元凶。这个场景最典型,也最省时间。
模拟故障演练。接口偶尔会挂,前端有没有做好兜底?把这个接口的 URL 屏蔽掉,再去操作页面,看看报错提示、重试机制、空态页面是不是符合预期。比让后端同事配合把接口停掉要快得多,而且你想测多少次都行。
定位超时和渲染阻塞。有时候一个请求不报错,但一直 pending,把主线程卡住。过去很难单独验证这个请求的影响,现在把它挡掉,对比 Performance 面板里的主线程任务和 FCP 指标,因果关系就清楚了。
临时关闭统计模块。做数据对比时,我想看看某个统计脚本是否影响了用户转化相关的事件上报,但不想动代码,也不想影响其它页面,那就只屏蔽统计脚本的请求。这个操作在前端数据分析场景里很实用。
这些场景的共同点是:你只关心某个特定的 URL 或特定的一类请求,不希望动其它请求,不想改代码,不想重新构建,更不想影响整个浏览器环境。有了单请求屏蔽能力,这些问题就变成了一个右键操作的事。
2. 功能入口与基本操作
2.1 一条规则拦住一个请求
先说最核心的用法。打开需要调试的页面,按 F12 或 Ctrl+Shift+I 打开开发者工具,切到 Network 面板。刷新一下页面,让请求列表加载出来,然后在列表里找到你想屏蔽的那个请求。
在这个请求上右键,菜单里会看到“Block request URL”的选项。不同版本里这个文案可能略有差异,有的叫“Block request”,有的直接显示“Block request URL”,意思是把这个 URL 加入屏蔽规则。点下去之后,这个请求会被加入规则列表,但表达上不会立即刷新页面,你需要再刷一次才能看到效果。
刷新之后你会发现,刚才那个请求在列表里变成了红色,状态栏会显示“blocked”,请求本身根本没有发出去。注意,是没有发出去,不是发出去之后被拒绝了。这跟服务端返回 4xx、5xx 是完全不同的情况。
这里有个操作技巧。如果请求是周期性触发的,比如每 30 秒一次的上报,你不需要一直守着面板刷新,可以先把 Network 面板顶部的过滤器打开,输入关键字把目标请求过滤出来,再右键操作。要是想快速验证规则有没有生效,还可以在请求上右键选择“Replay XHR”,单独重放一次,立刻就能看到它被拦截的结果。
2.2 域名级屏蔽与请求断点
“Block request URL”是最小粒度的操作,只挡住当前这个完整 URL。但有些场景下你不想挡完整地址,而是想挡整个域名的所有请求。右键菜单里还有一个“Block request domain”选项,选它会把该域名整体加入屏蔽规则。
这两个选项的区别一定要记清楚:URL 级屏蔽精确到某个具体的地址,比如只屏蔽统计上报的采集地址,不碰同域名的其它接口;域名级屏蔽则是把整个域名的所有请求全部挡掉。如果你不确定该用哪个,我建议先用 URL 级,因为它影响面小,误伤概率低。域名级屏蔽适合明确知道“这个域名下所有服务我都不要了”的情况。
除了屏蔽,右键菜单里还有个容易被忽略的“断点”操作。部分版本中你可以在请求上选择“Break on request URL”,下次这个请求发起时页面会暂停执行,你能在调用栈里清楚地看到是哪个脚本、哪一行代码发起的请求。这个功能特别适合排查“这个请求到底是谁调出来的”这种问题,它和屏蔽的区别在于:屏蔽是“不让它发出去”,断点是“让它发,但在发出去的瞬间按住暂停键,给你看清现场的机会”。
2.3 屏蔽规则的查看与管理
添加规则之后,不是就完事了,你还需要知道去哪管理这些规则。Network 面板的工具栏上有一个“Network request blocking”入口,点开之后会弹出一个设置面板,里面列出了当前所有被屏蔽的规则。
每条规则后面有开关和删除按钮。开关可以临时禁用某条规则,不用每次都删掉再加。如果你规则比较多,还能在这个面板里手动添加规则,支持通配符模式。比如你想屏蔽一类路径,可以写成类似*/api/report*的表达方式,它会按模式匹配命中。
这里必须要说一句:这个功能并不像临时变量那样只对当前标签页有效。规则是持久化存储的,刷新页面、切换标签页、甚至重启浏览器再打开,规则都还在。原因我后面会细讲,但你现在就得养成一个习惯:调试完后记得回来清理规则,否则很容易忘了自己之前屏蔽了什么。
3. 拦截工具背后的拦截逻辑
3.1 请求在被发出前就被拦下
我刚开始用这个功能时,有个疑问一直没想明白:它到底是在哪一层把请求挡住的?后来通过观察表现基本确认了,DevTools 的拦截位置在浏览器处理请求的早期阶段,也就是请求真正发送到服务端之前。
你看请求列表里的表现就明白了:被拦截的请求没有响应头,没有具体的时间线数据,状态就是“blocked”。说明它压根没有经历 DNS 查询、TCP 连接、服务端处理这些环节。这不是在网络上把它断掉,更像是在浏览器内部把它的出发闸门直接焊死了。
这一点对调试很重要。因为如果你是通过全局断网来模拟请求失败,页面里的图片、样式、脚本全部加载不出来,会产生大量脏数据干扰你的判断。而用单请求屏蔽,其它资源正常加载,只有目标请求消失,结果是干净且可对照的。
值得注意的是,被拦截的请求在瀑布流里会占据一条“blocked”的时间线。别小看这个细节,它能直观告诉你这个请求原本在哪一步被拦住,以及它的阻塞发生时点和页面加载阶段的关系。用 Performance 面板和 Network 面板对照着看,定位效率会高很多。
3.2 规则为什么能跨页面生效
很多人第一次用这个功能时会有一个疑问:我只是在当前页面加了一条屏蔽规则,为什么换个标签页打开,那个请求也被拦了?
答案是:这条规则根本不属于页面,而是属于 DevTools 自身的配置体系。浏览器把 URL 匹配规则持久化存储在当前用户配置目录中,页面只是规则的执行场景,而且规则的作用范围本来就是整个浏览器环境下的所有页面。
这个设计对调试来说非常友好。你想验证一个跨页面场景,比如从 A 页面跳转到 B 页面,两页都会发起同一个统计请求,你只需要在任意一个页面加一条规则,两个页面的该请求都会被拦下来。不需要重复配置。
但它也带来了一个管理和安全意识的问题。这条规则会在你不知不觉中影响所有标签页,如果你忘了清理就去访问其它站点,可能就会遇到“为什么某个功能失效了”的诡异现象。我的建议是,加规则之前先想好这次任务要做到哪一步,任务结束立刻把规则删掉,不留过夜规则。
3.3 它与底层拦截方案的本质区别
为了说清楚这个内置功能的价值,我觉得有必要把它和另外几种常见的拦截方案做个对比。我用一个表格来展示会更直观。
| 方案 | 拦截粒度 | 配置复杂度 | 影响范围 | 适用场景 |
|---|---|---|---|---|
| 浏览器扩展拦截 | 域名、URL 模式,通常偏粗糙 | 需要安装扩展并配置规则 | 当前浏览器全局生效 | 长期屏蔽广告、统计类请求 |
| 抓包工具/转发工具 | 可精确到单个 URL | 高,需要处理证书和转发链路 | 整个系统网络层 | 深度调试、修改请求响应内容 |
| 后端 Mock 服务 | 按接口路径匹配 | 中,需要单独启动服务 | 只影响当前 Mock 服务 | 模拟正常/异常接口数据 |
| DevTools 内建屏蔽 | 单个 URL 或单个域名 | 极低,右键即可 | 当前浏览器配置文件 | 调试时临时屏蔽单个请求 |
你看最后一行,粒度是最精细的,配置也是最简单的。扩展方案虽然也能做到域名级的过滤,但想精准到“只拦一个 URL,连它同域名下的另一个接口都不误伤”,很多扩展反而做不到。而且扩展的规则体系复杂,过滤语法要学习成本。
抓包工具能做到单 URL 拦截,但它改变的是整个网络层的行为,加上处理证书校验这些步骤,对只想快速验证一下的前端人员来说负担太重。DevTools 自带方案的价值在于:它在调试器内部完成拦截,不需要外部依赖,不做网络层的全局干扰,规则开关都在同一个面板里。
所以“Chrome 终于可以限制单个网络请求”这句话,真正的重点不是“能不能限制”,而是“能把限制的代价降到多低”。以前限制一个请求成本太高,现在右键一下就能搞定,这个转变才让很多原本懒得做的实验变成了日常操作。
4. 我的一次完整排查实战
4.1 触发场景与初步怀疑
有一次我在调一个内容页的性能,同事反馈说首屏转圈时间久。我打开 DevTools 看 Network,整页资源加载大体正常,但请求列表里有一条长尾请求特别扎眼,是一个第三方统计脚本的上报请求。这个请求加载倒是没失败,就是一直挂着,看起来像在等待。
但我不想只凭感觉说话。页面里同时还有另一个同域名的接口在提供核心功能,如果我用传统的“屏蔽整个域名”方式来做对照实验,那个核心接口也会一起挂掉,整个页面就会因为缺少基础数据而渲染失败,这样验证出来的结论根本没有说服力。
所以我决定用单个 URL 屏蔽来做一次干净的对照实验。目标很明确:只把这个统计上报请求挡住,保持场景中其它所有请求一切照旧,然后再看页面性能指标的变化。
4.2 用单个请求屏蔽定位真凶
操作很简单。我在 Network 面板中找到那条统计上报请求,右键,点击“Block request URL”,然后刷新页面。刷新后,这条请求在面板中立刻变成了 blocked 状态,其它脚本和接口全部正常加载。
接下来我重新记录了一次页面加载的数据:请求总数减少了那条上报,页面整体加载时间缩短了一截。然后我又切到 Performance 面板看主线程任务,发现原先卡住首屏渲染的那段长任务确实消失了。也就是说,这条统计请求不仅自身耗时,还阻塞了关键渲染链路的执行。
到这里还不能直接下结论。我把 Network request blocking 面板打开,把刚才那条规则临时停用,再次刷新页面,那条统计上报恢复了,页面加载时间也恢复到原来的慢速状态。来回对比了两次,现象一致,就能确认这个第三方脚本的加载方式和上报时机,确实影响了首屏的性能表现。
整个对比实验做完,大概用了十分钟,没有改一行代码,也没有影响任何其它功能的正常运行。放在以前,这种“只挡一个请求、不动其它任何东西”的对照实验,几乎是不可能在短时间内完成的。
4.3 复测与收尾
实验结论出来之后,我把规则从 Network request blocking 面板里删掉了。这一步看着不起眼,但特别重要。我认识不少朋友都在这个点上吃过亏,上午加了一条屏蔽规则,中午去验证别的页面时发现数据异常,排查了半天才发现是规则忘了关。
我习惯的做法是:每次加规则的时候,在笔记软件里顺手记一行,比如“正在调试屏蔽 xxx,验证完记得删”。这个习惯看起来有点笨,但它真的能救命,尤其是同时开多个调试任务的时候。
另外还要提醒一句,如果规则是用通配符模式添加的,删除的时候要确认自己删的是哪一条,不要手滑把别的规则关了。面板里规则多的时候,按作用域和路径仔细核对一下再操作。
5. 常见问题与排查技巧实录
5.1 为什么屏蔽了请求还是能发出去
我最常被问到的问题是:明明右键点了“Block request URL”,刷新页面后这个请求还是发出去了,这是怎么回事?
排查顺序一般是这样的。先打开 Network request blocking 面板,确认规则确实存在,并且开关是打开状态。接着看规则内容是不是有问题,如果你在屏蔽之前页面已经加载过当前 URL,并且浏览器有缓存,那请求可能直接从缓存里拿回来,这种时候要先把 Network 面板的“Disable cache”勾上,再做验证。
还有一种情况是页面使用了 Service Worker 来管理请求。Service Worker 在浏览器网络栈中有一个独立的处理层级,部分经过它处理的请求,尤其是预缓存请求,可能不会走常规的请求记录流程。遇到这种现象,建议先在 Application 面板里暂时停用 Service Worker,再做一次实验。
另外需要明确一点:这个屏蔽功能主要是针对页面里的子资源请求,比如脚本、样式、图片、接口、上报请求等。像地址栏直接访问一个页面、刷新主文档这种导航请求,不能用它来拦截,因为主文档请求没加载的话,页面本身都无法打开,DevTools 自然也就没有机会执行拦截动作。
5.2 规则冲突与删除混乱
有朋友在实验时同时添加了“Block request URL”和“Block request domain”两条规则,结果后续排查时发现请求依然被拦截,但想删除却找不到是哪条起了作用。
这个问题的根源在于规则之间存在重合。我的建议是,同一个请求不要同时添加两种粒度的规则。如果你已经有了完整 URL 的屏蔽规则,再看到一个域名级规则时,就要想想是不是自己之前手滑加错了。排查时可以把两条规则都先关闭,一个一个单独打开试验,确认哪条才是影响当前请求的规则,再决定删除哪条。
我自己在管理规则时的做法是:随手命名规则,尽量用明确包含路径的完整 URL。如果真的需要用通配符,也会在规则面板的备注里写清楚屏蔽意图(如果面板支持的话)。虽然这功能没有专门的备注字段,但你在外部笔记里备注一下,也是一个可行的办法。
5.3 一些容易被忽略的隐藏坑
快速整理几个我实际踩过的坑。
第一个是“Block request URL”和“Block request domain”的区别。我见过有人想屏蔽一个具体接口的请求,却点到了域名屏蔽,结果整个域名下所有资源全部失效。列表里一堆红色 block,场面一度非常壮观。动手前先看清楚菜单项。
第二个是屏蔽后的假象。你以为某个问题是因为请求被屏蔽导致的,但页面可能还有别的逻辑触发了同样的功能,导致数据重新生成。这种情况下,先看请求列表里有没有重复的 URL,以及有没有 Service Worker 的参与,不要急着下结论。
第三个是关于“Disable cache”的滥用。为了做对照实验,有人习惯把 Disable cache 一直开着,这会让页面加载状态偏离真实用户场景。我的建议是只在需要验证缓存行为时临时开启,做完实验立刻关掉,否则长时间开启会让性能数据完全失真。
第四个坑是规则残留。这我前面反复提过,但还是要再说一次:Chrome 的屏蔽规则不是临时性的,它会跨启动保留。如果你不是在独立测试配置环境里操作,请务必养成每次实验结束后检查规则列表的习惯。
6. 其他实用玩法与扩展思路
6.1 模拟接口故障的快速方式
对测试岗位的朋友来说,这个功能最大的价值就是可以近乎零成本地制造故障。以前想测一个接口挂了页面会不会崩,得等后端配合或者自己去服务端做手脚。现在你只要把那个接口单独屏蔽,页面前端面对的就是“请求无法发出”的状态,和真实网络不可用非常接近。
你可以做得更细致一些:先屏蔽单个接口,验证前端报错处理和重试逻辑;再屏蔽整个域名下的所有请求,验证页面在完全缺失某服务时的兜底表现。两个实验一气呵成,而且每个实验结束恢复也就几秒钟的事。
6.2 让嘈杂的请求安静下来
还有一个很实用的场景:页面里统计、广告、内容推荐类的请求特别多,把 Network 面板刷得乱七八糟,你根本看不清自己关心的资源。过去我只能通过过滤条件来“假装”它们不存在,但过滤只是隐藏,请求该发还是发,页面该卡还是会卡。
用这个屏蔽功能就可以做到“真的安静”。你不需要把它们全部屏蔽,只需要把几个高频上报的 URL 加入规则,刷一下页面,列表立刻干净很多。这时候再观察手写代码发起的关键请求,排障效率会高很多。
不过这里也提醒一句:如果你做的页面本来就是以统计上报作为核心功能,不要为了调试方便而长期屏蔽,不然你看到的只是一个没有噪音但也失去了真实行为的环境。
6.3 与清除缓存、硬刷新形成组合拳
做性能回归对比的时候,我经常把几个功能组合起来用,效果比单个功能好很多。
先打开 Network request blocking 面板,把目标请求加入屏蔽规则。然后回到 Network 面板勾上“Disable cache”,再用 Ctrl+R 做一次普通刷新。这样能确保目标请求被挡住,同时其它资源也没有被缓存干扰。记录完数据之后,把屏蔽规则删除,再把“Disable cache”取消,最后用 Ctrl+Shift+R 做一次硬刷新,恢复到一个相对真实的状态。
这套组合拳的唯一缺点,是操作步骤多了容易乱。所以我建议每做一步就在心里默念一下当前状态,或者干脆准备一张纸,写下当前是“屏蔽中”还是“已恢复”,避免在多个实验状态之间来回切换时搞混。
我在实际使用中最大的体会是,这类内建功能的关键不是功能本身有多复杂,而是它把调试的最小操作成本降到了一步以内。以前做一个“去掉某个请求看看结果”的实验,要把各种工具链都拉起来,现在只需要右键再刷新,这个效率提升对日常排障有着非常直接的好处。
最后再分享一个小习惯:每次加完屏蔽规则,我都会顺手在笔记里写一行,比如“调试中屏蔽了某个统计上报,下午删”。不是矫情,是踩过坑。这个功能最好的地方在于把单请求粒度的控制权交到开发者手里,但前提是规则记得收回来。用完就去 Network request blocking 里清理干净,别让它留在配置文件里影响后面的调试。觉得这功能值回票价的,可以在自己的项目里用它跑一遍第三方脚本排查,应该会有不少意外收获。