Puppeteer Browser.deleteCookie():按完整 Cookie 对象精确清除浏览器 Cookie 的官方 API
本文围绕 Puppeteer 的 Browser.deleteCookie() 方法展开:它是从默认 BrowserContext 中删除 Cookie 的快捷入口,接收一组完整的 Cookie 对象,通过"改写过期时间并重新写入"的方式实现删除。读完本文,你将掌握该方法的签名与参数语义、它与 setCookie/cookies/deleteMatchingCookies 的协作关系、CDP 与 WebDriver BiDi 两条协议链路下的实现差异,以及如何在测试中验证删除结果。
方法签名与参数
根据 API 文档,deleteCookie 的签名如下:
class Browser {
deleteCookie(...cookies: Cookie[]): Promise<void>;
}
- cookies:类型是
Cookie的展开参数(rest 参数)。注意这里要求传入的是Cookie而不是CookieData——Cookie是"从浏览器读回来的完整 Cookie",比用于写入的CookieData多要求path、expires、size、secure、session等字段。也就是说,你需要先拿到完整的 Cookie 描述才能精确删除它; - 返回值:
Promise<void>,方法异步执行,必须await后才能保证删除生效。
Cookie 接口的完整定义见 Cookie.ts:
export interface Cookie extends CookieData {
path: string; // Cookie 路径
expires: number; // UNIX 纪元秒数;-1 表示会话 Cookie
size: number; // Cookie 大小
secure: boolean; // 是否 Secure
session: boolean; // 是否会话 Cookie
partitionKeyOpaque?: boolean; // 分区键是否不透明(仅 Chrome)
}
而它继承的 CookieData 包含 name、value、domain、path?、secure?、httpOnly?、sameSite?、expires?、priority?、sourceScheme?、partitionKey? 等字段。其中 partitionKey 在 Chrome 中对应 CDP 的 topLevelSite 分区键,用于处理存储分区(CHIPS)场景。
实现原理:以"过期即删除"代替物理删除
在源码 Browser.ts 中,Browser.deleteCookie 本身是一个转发方法:
/**
* Removes cookies from the default {@link BrowserContext}.
*
* @remarks
*
* Shortcut for
* {@link BrowserContext.deleteCookie | browser.defaultBrowserContext().deleteCookie()}.
*/
async deleteCookie(...cookies: Cookie[]): Promise<void> {
return await this.defaultBrowserContext().deleteCookie(...cookies);
}
它只是默认浏览器上下文的快捷方式,真正的删除逻辑位于 BrowserContext.ts:
/**
* Removes cookie in this browser context.
*
* @param cookies - Complete {@link Cookie | cookie} object to be removed.
*/
async deleteCookie(...cookies: Cookie[]): Promise<void> {
return await this.setCookie(
...cookies.map(cookie => {
return {
...cookie,
expires: 1,
};
}),
);
}
可以看到,Puppeteer 并没有发送一条独立的"删除 Cookie"命令,而是将每个待删 Cookie 的 expires 覆盖为 1(即 1970-01-01 00:00:01 UTC,一个早已过去的时间戳),然后调用 setCookie 写回。浏览器存储层会按同名同域同路径的 Cookie 覆盖规则,把旧值替换为已过期条目,从而实现等效删除。
这一实现方式解释了两个实践要点:
- 参数必须"完整":由于删除走的是覆盖写路径,
name、domain、path等用于定位 Cookie 的字段必须准确,否则覆盖的是另一个键位的 Cookie 或新建了一个过期条目。这正是参数类型为Cookie(而非可选字段的CookieData)的原因; - 删除后应重新读取确认:测试中通常用
context.cookies()或页面内的document.cookie复核结果,仓库测试 browsercontext-cookies.test.ts 中"should delete cookies"用例就是这样做的——先设置cookie1、cookie2两个 Cookie,调用deleteCookie只删掉cookie1,随后断言document.cookie只剩'cookie2=2'。
底层协议链路
删除最终经由 setCookie 落到浏览器协议。以 CDP 链路为例,cdp/BrowserContext.ts 中的实现是:
override async setCookie(...cookies: CookieData[]): Promise<void> {
return await this.#connection.send('Storage.setCookies', {
browserContextId: this.#id,
cookies: cookies.map(cookie => {
return {
...cookie,
partitionKey: convertCookiesPartitionKeyFromPuppeteerToCdp(
cookie.partitionKey,
),
sameSite: convertSameSiteFromPuppeteerToCdp(cookie.sameSite),
};
}),
});
}
即最终发送 CDP 的 Storage.setCookies 命令,并附带 browserContextId,保证删除作用域限定在目标浏览器上下文内。BiDi 链路则在 bidi/BrowserContext.ts 实现了同名的 setCookie,走 WebDriver BiDi 的 storage API。因此在 CDP 与 BiDi 两种连接方式下,deleteCookie 的行为语义保持一致。
典型用法:读取—删除—验证
官方 Cookies 指南 给出了标准操作范式,完整示例如下(获取与写入部分用于构造删除所需的前置状态):
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
// 前置:写入两个 cookie(domain 为 localhost)
await browser.setCookie(
{
name: 'cookie1',
value: '1',
domain: 'localhost',
path: '/',
expires: -1,
httpOnly: false,
secure: false,
sourceScheme: 'NonSecure',
},
{
name: 'cookie2',
value: '2',
domain: 'localhost',
path: '/',
expires: -1,
httpOnly: false,
secure: false,
sourceScheme: 'NonSecure',
},
);
// 读取当前 cookie,拿到"完整 Cookie 对象"
const cookies = await browser.cookies();
// 删除其中指定的一批(此处删除 cookie1)
const target = cookies.find(c => c.name === 'cookie1');
if (target) {
await browser.deleteCookie(target);
}
console.log(await browser.cookies()); // 打印删除后的可用 cookie
推荐的工作流是:先 browser.cookies()(或 context.cookies())读取完整 Cookie 列表,再挑出目标对象传给 deleteCookie。这样能保证传入对象满足 Cookie 接口的全部必填字段,避免因字段缺失导致定位错误。
同一批方法在 BrowserContext 上同样可用(见指南结尾说明),例如:
const context = await browser.createBrowserContext();
await context.deleteCookie(
name: 'cookie1', value: '1', domain: 'localhost', path: '/',
expires: -1, size: 16, httpOnly: false, secure: false,
session: true, sourceScheme: 'NonSecure',
);
即 Browser 级方法操作的是默认上下文,BrowserContext 级方法可以操作任意(隔离)上下文,两者签名一致。
与 deleteMatchingCookies 的分工
deleteCookie 要求提供完整 Cookie,适合"我已经持有这个 Cookie 对象"的场景。如果只记得 Cookie 名、域名或 URL,仓库提供了按过滤器批量删除的 Browser.deleteMatchingCookies。从源码结构看(BrowserContext.ts),deleteMatchingCookies 的匹配逻辑是:
- 先
this.cookies()拉取上下文内全部 Cookie; - 对每个
DeleteCookiesRequest过滤器,name必须精确相等,然后domain、path、partitionKey、url(解析出 hostname 与 pathname 后精确比较)任一匹配即命中; - 最终收集所有命中的完整 Cookie,内部仍然调用
this.deleteCookie(...cookiesToDelete)完成删除。
这说明 deleteCookie(按完整对象)是删除链路的公共底座,而 deleteMatchingCookies 是它的"过滤器封装"。两者都返回 Promise<void>,用法上可按需选择:精确控制用前者,模糊批量清理用后者。此外 Page 级别还有 page.deleteCookie(...)(定义见 Page.ts),其参数是 DeleteCookiesRequest[],按当前页面的域自动限定范围,适合"清掉当前站点的某些 Cookie"这类页面级操作。
验证与测试依据
仓库中的测试覆盖了该方法的真实行为,可作为行为验证的参照:
- test/src/browsercontext-cookies.test.ts 的
BrowserContext.deleteCookies用例:设置两个会话 Cookie 后删除其一,通过page.evaluate(() => document.cookie)断言剩余值,直接验证了"过期覆盖"策略的可见效果; - test/src/defaultbrowsercontext.test.ts 中的
page.deleteCookie() should work用例,则验证了删除作用域限定在当前页面所属上下文的预期行为; - test/src/cookies.test.ts 的
Page.deleteCookie一组用例进一步覆盖了按{name, domain, path}过滤器删除、以及"按指定 URL 删除 cookie 与当前页面无关"等边界行为。
小结
| 要点 | 说明 |
|---|---|
| 定位 | Browser.deleteCookie 是 browser.defaultBrowserContext().deleteCookie(...) 的快捷方式(见 docs/api/puppeteer.browser.deletecookie.md) |
| 参数 | rest 形式的完整 Cookie 对象数组,name/domain/path 等定位字段必须准确 |
| 机制 | 将 expires 改写为 1 后经 setCookie → CDP Storage.setCookies(或 BiDi storage API)覆盖写回,等效删除 |
| 作用域 | 默认浏览器上下文;隔离场景改用 BrowserContext.deleteCookie |
| 配套 | 模糊删除用 deleteMatchingCookies;页面级删除用 page.deleteCookie |
| 验证 | 删除后以 cookies() 或页面 document.cookie 复核,参照 test/src/browsercontext-cookies.test.ts 的断言方式 |
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 StartedRust0623
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