Puppeteer Page.setRequestInterception() 全解析:开启请求拦截、阻塞与改写网络请求的完整指南
2026/9/8 21:36:58 网站建设 项目流程

Puppeteer Page.setRequestInterception() 全解析:开启请求拦截、阻塞与改写网络请求的完整指南

【免费下载链接】puppeteerJavaScript API for Chrome and Firefox项目地址: https://gitcode.com/GitHub_Trending/puppeteer1/puppeteer

网络拦截是浏览器自动化中高频使用的核心能力。本文以 Puppeteer 官方 API 文档 Page.setRequestInterception() 为主线,系统讲解该方法的方法签名、拦截开启后的请求停滞模型、配套的 HTTPRequest.abort() / HTTPRequest.continue() / HTTPRequest.respond() 三件套,并结合仓库中的源码与示例,给出可直接运行的实战代码。读完本文,你将掌握拦截任意请求并实现"屏蔽图片、改写请求头、模拟响应、阻断特定域名"等方案的完整技能。

方法签名与语义

setRequestInterception()在 Page 抽象类 中被声明为抽象方法,其完整签名如下:

class Page { abstract setRequestInterception(value: boolean): Promise<void>; }

对应的接口定义位于仓库 packages/puppeteer-core/src/api/Page.ts。参数说明如下:

参数类型说明
valueboolean是否开启请求拦截。传true开启,传false关闭

调用会返回Promise<void>。从源码结构看,该方法在 Page 抽象类 中仅为abstract声明,实际行为由不同浏览器引擎的实现类提供——CDP(Chrome DevTools Protocol)方向的实现在 packages/puppeteer-core/src/cdp/Page.ts,WebDriver BiDi 方向的实现在 packages/puppeteer-core/src/bidi/Page.ts,二者在网络请求的底层拦截与"放行/中止/应答"协调逻辑最终汇聚到对应的网络管理器(例如 packages/puppeteer-core/src/cdp/NetworkManager.ts)。

开启拦截的三个直接效果

官方文档明确了拦截开启后的行为语义,理解这一点是正确使用的前提:

  1. 激活三件套能力:开启请求拦截后,HTTPRequest.abort()(中止请求)、HTTPRequest.continue()(继续请求)、HTTPRequest.respond()(伪造响应)三种方法才可用,从而获得修改页面发起的网络请求的能力。
  2. 请求停滞模型:一旦开启拦截,每一个请求都会停滞(stall),除非它被显式continue(继续)、respond(应答)或abort(中止),或者命中浏览器缓存直接完成。这意味着一旦开启拦截却不在request事件中处理请求,页面导航与资源加载将被卡死。
  3. 幂等开启:由于方法接受布尔值,需要关闭拦截时调用await page.setRequestInterception(false)即可。

提示:关闭拦截只影响之后的行为。如果你只在request监听器里对满足条件的请求调用abort(),必须记得在else分支对不满足条件的请求调用continue(),否则页面会永久停滞。

一个容易忽略的联动点:HTTP 认证

值得留意的是,Page.authenticate()(HTTP 认证)的实现会在后台自动开启请求拦截(该方法文档中的:::note明确写道"Request interception will be turned on behind the scenes to implement authentication. This might affect performance.")。也就是说拦截与认证共享同一套底层机制,频繁开合拦截、叠加使用认证会带来性能开销,在使用时需要有所预期。

拦截的三把钥匙:abort / continue / respond

请求停滞之后,开发者正是通过监听request事件并调用 HTTPRequest 的三种终结方法来决定每个请求的去向。

abort:直接中止请求

签名与参数:

class HTTPRequest { abort(errorCode?: ErrorCode, priority?: number): Promise<void>; }
参数类型说明
errorCodeErrorCode(可选)提供给请求的错误码,缺省时由实现决定
prioritynumber(可选)若提供,则按"协作式处理"规则解析拦截;否则立即解析

其中 ErrorCode 是一组字符串字面量联合类型,完整取值如下:

export type ErrorCode = | 'aborted' | 'accessdenied' | 'addressunreachable' | 'blockedbyclient' | 'blockedbyresponse' | 'connectionaborted' | 'connectionclosed' | 'connectionfailed' | 'connectionrefused' | 'connectionreset' | 'internetdisconnected' | 'namenotresolved' | 'timedout' | 'failed';

重要前提:abort 的官方说明 强调,使用它之前必须通过Page.setRequestInterception(true)开启拦截,否则该方法会立即抛出异常。这也是continuerespond两条文档中重复出现的前提约束。

continue:按原样或改写后继续请求

签名与参数:

class HTTPRequest { continue( overrides?: ContinueRequestOverrides, priority?: number, ): Promise<void>; }

overrides的类型为 ContinueRequestOverrides,其可选字段如下:

字段类型说明
headersRecord<string, string>覆盖请求头
methodstring覆盖 HTTP 方法
postDatastring覆盖 POST 请求体
urlstring改写请求 URL(注意:这是改写而非重定向,请求去向会改变)

priority语义与abort一致:提供则按协作式规则解析,否则立即解析。一个改写请求头的标准示例:

await page.setRequestInterception(true); page.on('request', request => { // 覆盖请求头:设置 "foo",移除 "origin" const headers = Object.assign({}, request.headers(), { foo: 'bar', origin: undefined, }); request.continue({headers}); });

respond:直接伪造响应

签名与参数:

class HTTPRequest { respond( response: Partial<ResponseForRequest>, priority?: number, ): Promise<void>; }

response的类型为Partial<[ResponseForRequest](https://link.gitcode.com/i/724d897d3eb187f6590551e144f18075)>。其完整字段定义如下:

字段类型说明
statusnumberHTTP 状态码
headersRecord<string, string \| string[] \| unknown>(可选)响应头。数组值会逐项映射为 String,用于同名多值头;非数组值转换为 String
contentTypestringContent-Type 响应头
bodystring \| Uint8Array响应体,支持字符串或二进制字节流

文档给出的"把所有请求都伪造成 404"的示例:

await page.setRequestInterception(true); page.on('request', request => { request.respond({ status: 404, contentType: 'text/plain', body: 'Not Found!', }); });

注意:respond 的文档 特别说明,dataURL请求调用respond是一个 noop(空操作),即无法为data:协议请求伪造响应。

从文档示例出发:阻断全部图片请求

官方文档给出的"朴素版拦截器"直接演示了开启拦截 + 事件监听 + abort/continue 分流的最小完整闭环,代码位于 setRequestInterception 方法文档:

import puppeteer from 'puppeteer'; const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.setRequestInterception(true); page.on('request', interceptedRequest => { if ( interceptedRequest.url().endsWith('.png') || interceptedRequest.url().endsWith('.jpg') ) interceptedRequest.abort(); else interceptedRequest.continue(); }); await page.goto('https://example.com'); await browser.close();

逐行拆解其执行脉络:

  1. puppeteer.launch()启动浏览器,browser.newPage()新建标签页;
  2. await page.setRequestInterception(true)开启拦截——从此刻起页面发出的请求进入停滞状态;
  3. page.on('request', ...)注册监听器:每个请求到达时,先判断 URL 是否以.png/.jpg结尾;
  4. 命中则调用interceptedRequest.abort()让请求失败(页面表现为图片加载失败但页面主体继续渲染);
  5. 未命中则调用interceptedRequest.continue()放行,这是防止页面卡死的关键 else 分支
  6. page.goto()导航并等待页面加载,最后browser.close()关闭。

更贴近实战的变体与扩展场景

仓库中的示例 examples/block-images.js 给出了一个更适合真实页面的写法:不再用 URL 后缀猜测,而是直接按资源类型判断。请求的资源类型可通过 HTTPRequest.resourceType() 获得(其类型定义为Lowercase<Protocol.Network.ResourceType>,即渲染引擎视角下的资源类型):

import puppeteer from 'puppeteer'; const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.setRequestInterception(true); page.on('request', request => { if (request.resourceType() === 'image') { request.abort(); } else { request.continue(); } }); await page.goto('https://news.google.com/news/'); await page.screenshot({path: 'news.png', fullPage: true}); await browser.close();

与官方文档示例相比,resourceType() === 'image'能一次性覆盖 CSS 背景图、<picture>源图、SVG 内嵌图等多种形态,而不仅限于.png/.jpg两种后缀,这也是该示例注释所强调的"屏蔽图片、节省带宽、加速整页截屏"用法。该模式正是做整页截图、页面性能分析时去除干扰资源的常用手段。

在真实工程中,你往往还需要把这些手法组合成更细的规则。下面给出一个可运行的综合示例:同时屏蔽图片、改写第三方统计请求头、并把某个 API 的请求伪造成本地数据:

import puppeteer from 'puppeteer'; const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.setRequestInterception(true); page.on('request', request => { const url = request.url(); // 1) 屏蔽图片类资源 if (request.resourceType() === 'image') { return request.abort(); } // 2) 伪造对特定接口的响应(例如注入桩数据) if (url.endsWith('/api/config')) { return request.respond({ status: 200, contentType: 'application/json', body: JSON.stringify({featureFlags: {newHome: true}}), }); } // 3) 对第三方统计域名只放行但附加标记头 if (url.includes('analytics.example.com')) { return request.continue({ headers: {...request.headers(), 'x-pptr-tagged': '1'}, }); } // 4) 其余请求一律放行 return request.continue(); }); await page.goto('https://example.com'); await browser.close();

底层实现与注意事项(源码视角)

最后回到仓库源码层面,帮助你建立对这套机制的准确预期:

  • 接口抽象:Page.setRequestInterception 在 API 层只是抽象声明,参数value的 JSDoc 注释与公开文档逐字对应("Whether to enable request interception"),保证文档与类型签名一致。
  • 引擎分派:Chrome/Chromium 走 CDP 实现(cdp/Page.ts 及 cdp/NetworkManager.ts),Firefox 等走 WebDriver BiDi 实现(bidi/Page.ts),底层分别依赖各自的 Fetch / Network 域协议。仓库测试 NetworkManager.test.ts 覆盖了拦截逻辑的编排细节。
  • 性能与纪律:开启拦截后"每个请求都会停滞"意味着所有网络事件都要经过 Node 侧处理再放回浏览器,吞吐必然下降;因此拦截只应在确有需要的场景开启,处理完毕记得setRequestInterception(false)关闭。另外务必保证每个请求都有且仅有一次终结调用,并尽量让abort/continue/respond的分支互斥,避免同一请求被重复解析。

小结

  • page.setRequestInterception(true)开启拦截后,页面请求全部停滞,必须通过request事件对每个请求调用abort()/continue()/respond()之一,或让请求命中浏览器缓存。
  • abort(errorCode?)直接中止请求并支持 14 种 ErrorCode;continue(overrides?)可改写请求头、方法、POST 体甚至 URL;respond(response?)可用 ResponseForRequest 字段伪造状态码、响应头与响应体。
  • 未开启拦截就调用三件套会立即抛异常;dataURL请求无法被respond伪造;HTTP 认证会在后台自动开启拦截。
  • 结合 examples/block-images.js 的资源类型判断写法,可以低成本实现图片屏蔽、请求改写与响应桩等常见自动化需求。

【免费下载链接】puppeteerJavaScript API for Chrome and Firefox项目地址: https://gitcode.com/GitHub_Trending/puppeteer1/puppeteer

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询