Puppeteer HTTPRequest.resourceType() 详解:按资源类型拦截与筛选页面请求
本篇指南围绕 Puppeteer 的 HTTPRequest.resourceType() 方法展开,讲解它是如何返回渲染引擎所感知的请求资源类型、其返回的 ResourceType 取值集合与底层数据来源,并结合本仓库的真实示例(拦截图片加载)与测试用例,给出可按需复用的请求过滤与拦截方案。读完你将掌握如何用 page.on('request') + resourceType() 实现对页面各类网络资源的精细化管控(拦截、放行、统计与降载),并能理解该方法在 Chrome(CDP)与 Firefox(WebDriver BiDi)两条实现路径上的行为差异。
本方法属于 HTTPRequest 类,其 API 参考见 docs/api/puppeteer.httprequest.resourcetype.md。
方法签名与返回类型
resourceType() 是定义在抽象基类 HTTPRequest 上的抽象方法,其原始 API 文档给出如下签名:
class HTTPRequest {
abstract resourceType(): ResourceType;
}
它"包含渲染引擎所感知到的请求资源类型"(Contains the request's resource type as it was perceived by the rendering engine),无参数,直接返回 ResourceType。
在源码中,该抽象方法的声明位于 packages/puppeteer-core/src/api/HTTPRequest.ts#L278-L282。与其配套的 ResourceType 类型同样定义在该文件中:
export type ResourceType = Lowercase<Protocol.Network.ResourceType>;
也就是说,ResourceType 本质上是 Chrome DevTools Protocol(CDP)中 Network.ResourceType 枚举的全小写形式,来自 devtools-protocol 包(参见同文件顶部的 import type {Protocol} from 'devtools-protocol')。因此 resourceType() 的返回值永远是小写字符串,常见取值包括:
| 取值(小写) | 对应的资源类别 |
|---|---|
document |
顶层/子框架的 HTML 文档(导航请求) |
stylesheet |
CSS 样式表 |
image |
图片资源 |
media |
音视频媒体 |
font |
字体文件 |
script |
JavaScript 脚本 |
xhr |
XMLHttpRequest 发起的请求 |
fetch |
fetch() API 发起的请求 |
eventsource |
Server-Sent Events(EventSource) |
websocket |
WebSocket 连接 |
manifest |
Web App Manifest |
texttrack、ping、prefetch、preflight、signedexchange、cspviolationreport 等 |
更细分的浏览器资源类别 |
other |
未能归入上述类别的请求(兜底值) |
取值全集由 CDP 协议定义,
ResourceType只是对它做Lowercase映射。这意味着做等值比较时务必使用小写,例如request.resourceType() === 'image',写成'Image'会永远匹配失败。
数据从哪来:CDP 实现中的存储与兜底
resourceType() 在 Chrome(CDP)实现中由 CdpHTTPRequest 提供,见 packages/puppeteer-core/src/cdp/HTTPRequest.ts#L140-L142。关键逻辑发生在构造函数里:
this.#resourceType = (data.type || 'other').toLowerCase() as ResourceType;
(见 packages/puppeteer-core/src/cdp/HTTPRequest.ts#L100)
由此可以得出三点实现事实:
- 值来自浏览器侧:
data.type即 CDPNetwork.requestWillBeSent等事件携带的type字段,由 Chrome 渲染引擎在发出请求时打上分类标签,Puppeteer 只负责接收和转存,并不自行推断资源类型。 - 缺失时兜底为
other:当协议事件未携带type字段时,会被记录为'other',这与 BiDi 实现中的兜底策略一致(见下文)。 - 小写归一化在构造时完成:存入字段时已经
.toLowerCase(),因此后续每次调用resourceType()都是纯字段读取,无额外开销。
典型实战:用 request 拦截按资源类型放行或阻断
resourceType() 最常见的应用场景是与 page.setRequestInterception(true) 配合,在 request 事件中按资源类型决定是 abort() 还是 continue()。本仓库给出了一个完整可运行的真实示例 examples/block-images.js:
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();
这段代码展示了最经典也最实用的"屏蔽图片以加速加载"的写法:监听 page 上的 request 事件,凡是 resourceType() === 'image' 的请求一律 abort(),其余请求放行,最后整页截图并关闭浏览器。同样的模式稍作修改即可扩展出更多场景:
- 按类型过滤做统计埋点:不拦截,仅记录
request.url()与request.resourceType(),即可分析一个页面发出的各类资源占比(比如统计xhr/fetch接口请求数量)。 - 只放行某类资源:例如对
font请求执行abort()以规避字体版权加载、降低流量;对media请求abort()以阻止自动播放的视频下载。 - 优先处理导航请求:通过
document类型配合 isNavigationRequest() 判断请求是否为当前框架的导航驱动请求,从而在拦截链上对页面跳转与子资源区别对待。
需要留意,若想以 continue()/respond()/abort() 之一处理拦截,必须先调用 page.setRequestInterception(true),否则这些方法会直接抛错;完整的拦截语义与协作式优先级可参考 HTTPRequest.abort、HTTPRequest.continue 与 HTTPRequest.respond 的文档。
跨浏览器差异:Firefox(WebDriver BiDi)实现的行为限制
Puppeteer 同时支持 Chrome 与 Firefox。Firefox 走 WebDriver BiDi 协议,其实现位于 packages/puppeteer-core/src/bidi/HTTPRequest.ts#L149-L156:
override resourceType(): ResourceType {
if (!this.#frame.page().browser().cdpSupported) {
throw new UnsupportedOperation();
}
return (this.#request.resourceType || 'other').toLowerCase() as ResourceType;
}
从源码可以明确两点:
- 当通过纯 WebDriver BiDi 连接 Firefox、浏览器不支持 CDP(
cdpSupported为假)时,调用resourceType()会抛出 UnsupportedOperation 异常——资源类型分类是 CDP 提供的能力,BiDi 协议本身并不总能给出等价信息。 - 在支持 CDP 的通道上,BiDi 实现同样做了小写归一化与
other兜底,与 CDP 实现保持一致。
因此在编写跨浏览器自动化脚本时,若需兼容纯 BiDi 环境,应把 resourceType() 的调用放进能力检测或 try/catch 中,避免因该特性不可用而中断整个拦截流程。
正确性由测试守护:相关测试用例
仓库的测试套件中对 resourceType() 的行为有直接断言,见 test/src/network.test.ts#L1036-L1064 中的 Request.resourceType 分组:
- document 类型:
page.goto(server.EMPTY_PAGE)后取响应对应请求,断言request.resourceType()等于'document'; - stylesheet 类型:加载含单一样式表的页面
one-style.html,在request事件中捕获.css请求,断言其resourceType()等于'stylesheet',且 URL 包含one-style.css。
这两条用例不仅验证了返回值的小写形态,也印证了"资源类型随真实页面加载产生、可通过 request 事件捕获"这一核心用法。类似的断言还出现在 test/src/requestinterception.test.ts 与 test/src/requestinterception-experimental.test.ts,它们与拦截场景共同构成了该方法的功能回归保障。
使用要点小结
- 返回值恒为小写:直接与
'document'、'stylesheet'、'image'等字面量比较即可,无需额外处理大小写。 - 语义来自浏览器:资源类型由渲染引擎判定并随协议事件下发,Puppeteer 不做猜测;缺失时统一兜底为
'other'。 - 最常用在 request 拦截中:先
page.setRequestInterception(true),再在request事件中按resourceType()分流调用abort()/continue()/respond()。 - 注意跨协议差异:纯 WebDriver BiDi(无 CDP 支持)的 Firefox 场景下该方法可能抛出
UnsupportedOperation,跨浏览器代码需做兼容处理。 - 配合其他方法使用:结合 HTTPRequest.url()、HTTPRequest.method() 与 HTTPRequest.isNavigationRequest() 可获得请求的完整画像,实现更精准的过滤与观察逻辑。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00