首页
/ Puppeteer HTTPRequest.resourceType() 详解:按资源类型拦截与筛选页面请求

Puppeteer HTTPRequest.resourceType() 详解:按资源类型拦截与筛选页面请求

2026-09-06 19:17:11作者:郁楠烈Hubert

本篇指南围绕 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
texttrackpingprefetchpreflightsignedexchangecspviolationreport 更细分的浏览器资源类别
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

由此可以得出三点实现事实:

  1. 值来自浏览器侧data.type 即 CDP Network.requestWillBeSent 等事件携带的 type 字段,由 Chrome 渲染引擎在发出请求时打上分类标签,Puppeteer 只负责接收和转存,并不自行推断资源类型。
  2. 缺失时兜底为 other:当协议事件未携带 type 字段时,会被记录为 'other',这与 BiDi 实现中的兜底策略一致(见下文)。
  3. 小写归一化在构造时完成:存入字段时已经 .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.abortHTTPRequest.continueHTTPRequest.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;
}

从源码可以明确两点:

  1. 当通过纯 WebDriver BiDi 连接 Firefox、浏览器不支持 CDPcdpSupported 为假)时,调用 resourceType() 会抛出 UnsupportedOperation 异常——资源类型分类是 CDP 提供的能力,BiDi 协议本身并不总能给出等价信息。
  2. 在支持 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.tstest/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() 可获得请求的完整画像,实现更精准的过滤与观察逻辑。
登录后查看全文
热门项目推荐
相关项目推荐