首页
/ Electron Cookies API 详解:Session 级 Cookie 的查询、写入、删除与变更监听完整指南

Electron Cookies API 详解:Session 级 Cookie 的查询、写入、删除与变更监听完整指南

2026-09-05 09:37:21作者:舒璇辛Bertina

本文围绕 Electron 的 Cookies 类 API 展开,完整覆盖 docs/api/cookies.md 中定义的实例事件与四个实例方法,并结合浏览器进程侧的 C++ 实现(shell/browser/api/electron_api_cookies.cc)与官方测试用例(spec/api-session-spec.ts)解释每个参数在底层是如何解析和生效的。读完本文,你可以掌握在 Electron 主进程中按 URL/域名/属性精确查询 Cookie、正确设置 SameSite 与安全属性、删除指定 Cookie、控制 Cookie 落盘时机,以及如何通过 changed 事件监听 Cookie 的全生命周期变化。

1. Cookies 类的定位与获取方式

Cookies 类用于查询和修改某个 Session 的 Cookie("Query and modify a session's cookies")。它有两个关键特性,决定了使用姿势:

  • 只在主进程可用Cookies 属于 Main Process 的 API;
  • 不从 'electron' 模块导出:它只能通过其他 API 的返回值获得,即作为 Sessioncookies 属性访问。
const { session } = require('electron')

// 查询所有 cookies。
session.defaultSession.cookies.get({})
  .then((cookies) => {
    console.log(cookies)
  }).catch((error) => {
    console.log(error)
  })

// 查询与某个 URL 关联的所有 cookies。
session.defaultSession.cookies.get({ url: 'https://www.github.com' })
  .then((cookies) => {
    console.log(cookies)
  }).catch((error) => {
    console.log(error)
  })

// 设置一个 cookie;若存在等价 cookie 则覆盖。
const cookie = { url: 'https://www.github.com', name: 'dummy_name', value: 'dummy' }
session.defaultSession.cookies.set(cookie)
  .then(() => {
    // success
  }, (error) => {
    console.error(error)
  })

从源码结构看,每个 Cookies 实例在构造时持有一个 ElectronBrowserContext*(见 shell/browser/api/electron_api_cookies.h 中的 browser_context_ 成员),并且所有 get/set/remove/flushStore 操作都通过 browser_context_->GetDefaultStoragePartition()->GetCookieManagerForBrowserProcess() 拿到对应的 Cookie 管理器来执行。这意味着 Cookie 是按 Session(及其底层的 BrowserContext)隔离的defaultSession 与各 session.fromPartition('...') 分区各自拥有独立的 Cookie 存储。测试中也是通过 testSession.cookies.set/get 在分区会话上独立操作验证了这一点(见 spec/api-session-spec.tstestSession.cookies 相关断言)。

2. 返回值中的 Cookie 对象结构

所有查询结果与变更事件中的 cookie 参数都是 Cookie Object,字段如下:

字段 类型 说明
name string Cookie 名称
value string Cookie 值
domain string(可选) Cookie 域名;会规范化为带前导点的形式,使其对子域名同样有效
hostOnly boolean(可选) 是否为 host-only cookie;仅在设置时未传 domain 时才可能为 true
path string(可选) Cookie 路径
secure boolean(可选) 是否标记为 Secure
httpOnly boolean(可选) 是否标记为 HTTP Only
session boolean(可选) 是会话 Cookie 还是带过期时间的持久 Cookie
expirationDate Double(可选) 过期时间,UNIX 纪元起的秒数;会话 Cookie 不提供该字段
sameSite string Same Site 策略:unspecifiedno_restrictionlaxstrict

这个结构不是手工拼装的,而是由 C++ 转换器直接从 net::CanonicalCookie 生成:shell/browser/api/electron_api_cookies.cc 中的 Converter<net::CanonicalCookie> 会把 Chromium 网络栈的规范化 Cookie 逐字段映射为 JS 对象,其中 hostOnlynet::cookie_util::DomainIsHostOnly 判定,session!val.IsPersistent() 得出——这也解释了为什么文档规定 expirationDate 只在持久 Cookie 上出现。

3. 实例事件:changed

Cookies 实例支持如下事件:

事件:changed

返回值参数:

  • event Event
  • cookie Cookie — 发生变化的那个 Cookie
  • cause string — 变更原因,取以下值之一:
    • inserted — Cookie 被插入。
    • inserted-no-change-overwrite — 新插入的 Cookie 覆盖了旧 Cookie 但没有产生任何变化(例如插入一个完全相同的 Cookie)。
    • inserted-no-value-change-overwrite — 新插入的 Cookie 覆盖了旧 Cookie,值没有变化,但对 Web 可观测(例如更新了过期时间)。
    • explicit — Cookie 被消费者直接删除。
    • overwrite — Cookie 因一次覆盖写入操作而被自动移除。
    • expired — Cookie 因过期被自动移除。
    • evicted — Cookie 在垃圾回收过程中被自动逐出。
    • expired-overwrite — Cookie 被写入一个已经过期的过期时间而覆盖。
  • removed boolean — 若该 Cookie 被移除则为 true,否则为 false

当某个 Cookie 因新增、编辑、删除或过期而发生变化时触发。

3.1 变更通知的底层链路

从源码看,这条链路分为两跳:

  1. 网络进程到浏览器进程Cookies 构造函数中通过 browser_context_->cookie_change_notifier()->RegisterCookieChangeCallback(...) 订阅变更回调。CookieChangeNotifiershell/browser/cookie_change_notifier.h)实现了 network::mojom::CookieChangeListener 接口,把网络服务的 Mojo Cookie 变更通知转发到 UI 线程,再分发给所有注册者。

  2. 事件发射与 removed 的判定Cookies::OnCookieChangedshell/browser/api/electron_api_cookies.cc#L456-L463)收到 net::CookieChangeInfo 后,调用 IsDeletion(change.cause) 计算第三个参数 removed,然后以 Emit("changed", cookie, cause, removed) 发出事件。

关于 cause 到字符串的映射与 removed 的判定逻辑,可以直接在 shell/browser/api/electron_api_cookies.ccConverter<net::CookieChangeCause>同文件的 IsDeletion 函数 中一一对应:insertedinserted-no-change-overwriteinserted-no-value-change-overwrite 三类对应 removed = false,其余原因(explicit/overwrite/expired/evicted/expired-overwrite)均视为删除,removed = true。这与文档中各 cause 的语义描述完全一致。

官方测试 spec/api-session-spec.ts 中的 collectCookieChanges 辅助函数展示了监听 changed 事件的典型用法:注册监听器 → 执行 set/remove 等动作 → 按收到的变更条数收集 { cause, cookie, removed },可用于回归验证 Cookie 生命周期行为。

4. cookies.get(filter):按条件查询 Cookie

cookies.get(filter)

  • filter Object
    • url string(可选)— 获取与该 url 关联的 Cookie;留空表示获取所有 URL 的 Cookie。
    • name string(可选)— 按名称过滤。
    • domain string(可选)— 获取域名匹配 domain 或其子域名的 Cookie。
    • path string(可选)— 获取路径匹配 path 的 Cookie。
    • secure boolean(可选)— 按 Secure 属性过滤。
    • session boolean(可选)— 过滤会话 Cookie 或持久 Cookie。
    • httpOnly boolean(可选)— 按 httpOnly 过滤。

返回 Promise<Cookie[]>,解析为一个 Cookie 对象数组。语义是“发送请求获取所有匹配 filter 的 Cookie 并解析 Promise”。

4.1 两条查询路径(源码层面)

Cookies::Get 的实现(shell/browser/api/electron_api_cookies.cc#L310-L340)按 url 是否为空分两条路径:

  • url 为空:调用 CookieManager::GetAllCookies,拿到全量 Cookie 后在 Electron 侧用 MatchesCookie 做二次过滤;
  • url 非空:调用 CookieManager::GetCookieList(GURL(url), options, ...),并设置了三个关键的 net::CookieOptions
    • set_include_httponly() — 保证 HTTP-only Cookie 也会被返回(即主进程 API 不受 httpOnly 限制);
    • set_same_site_cookie_context(SameSiteCookieContext::MakeInclusive()) — 让查询不受 SameSite 限制条件约束;
    • set_do_not_update_access_time()查询本身不会更新 Cookie 的访问时间,这对依赖“过期即清除”语义的应用很重要。

过滤逻辑 MatchesCookie同文件 L110-L129)与文档参数表一一对应:name/path 为字符串精确比较,domain 使用 cookie.IsDomainMatch(*str)(因此文档说“域名匹配或是其子域”),secure/session/httpOnly 为布尔比较。测试中用 cookies.get({ domain: '127.0.0.1' }) 验证了不传 url 时按域名过滤可以命中之前对具体 URL 写入的 Cookie(spec/api-session-spec.ts#L156-L164)。

5. cookies.set(details):写入 Cookie 的完整参数

cookies.set(details)

  • details Object
    • url string — 与 Cookie 关联的 URL;URL 非法时 Promise 会被拒绝。
    • name string(可选)— Cookie 名称,省略时默认为空。
    • value string(可选)— Cookie 值,省略时默认为空。
    • domain string(可选)— Cookie 域名,会规范化为带前导点的形式以便对子域名生效;省略时默认为空。
    • path string(可选)— Cookie 路径,省略时默认为空。
    • secure boolean(可选)— 是否标记为 Secure。默认 false,但使用 Same Site=None 属性时除外。
    • httpOnly boolean(可选)— 是否标记为 HTTP Only,默认 false
    • expirationDate Double(可选)— 过期时间,UNIX 纪元起的秒数;省略时 Cookie 成为会话 Cookie,不会跨会话保留。
    • sameSite string(可选)— 对该 Cookie 应用的 Same Site 策略,可取 unspecifiedno_restrictionlaxstrict,默认 lax

返回 Promise<void>,Cookie 设置成功后解析。

5.1 参数解析细节(源码印证)

Cookies::Set 的实现(shell/browser/api/electron_api_cookies.cc#L366-L441)确认了几个容易踩坑的细节:

  1. url 是强制项:缺失时立即拒绝并提示 "Missing required option 'url'";URL 无法解析为合法 GURL 时,会以 EXCLUDE_INVALID_DOMAIN 的原因拒绝 Promise。
  2. sameSite 默认值与取值StringToCookieSameSite同文件 L262-L282)在未传 sameSite 时落到 LAX_MODE,即默认 lax;传入其他字符串(如 'garbage')会拒绝并抛出 "Failed to convert 'garbage' to an appropriate cookie same site value"——测试 spec/api-session-spec.ts#L148-L154 正是断言了这条错误消息。
  3. secure 的隐式默认:源码中 secure = details.FindBool("secure").value_or(same_site == NO_RESTRICTION),即 sameSiteno_restriction 而未显式指定 secure 时,secure 自动取 true。这正是文档那句“Defaults to false unless Same Site=None attribute is used”的出处。
  4. name/value 可省略但会创建空名 Cookie:未提供时以空字符串参与 net::CanonicalCookie::CreateSanitizedCookie 构造;测试“sets cookies without name”验证了此时取回的 Cookie name 为空字符串、value 正常(spec/api-session-spec.ts#L126-L134)。
  5. 落库失败的原因会翻译成可读错误:当 CreateSanitizedCookie 产出非法 Cookie 或 SetCanonicalCookie 返回的访问状态不是 include 时,Promise 会以 InclusionStatusToString 生成的错误文本拒绝。该函数(同文件 L161-L260)把 net::CookieInclusionStatus::ExclusionReason 逐一映射为英文原因,例如“域名不匹配”“Cookie 超过 name/value 尺寸上限”“包含非 ASCII 域”“Secure Cookie 不允许被非 Secure 写入覆盖”等——实际排错时应直接阅读拒绝 Promise 抛出的这段文本。

此外,从源码结构看,Set 还会从 details 中读取 creationDatelastAccessDate(通过 ParseTimeProperty(details.FindDouble(...)) 解析),尽管文档参数表未列出这两项,它们同样以 UNIX 纪元秒数接受并可影响 Cookie 的创建/访问时间戳。

5.2 会话 Cookie 与持久 Cookie 的验证

测试用例给出了两组对照(spec/api-session-spec.ts#L102-L124):

// 持久 Cookie:带 expirationDate
await cookies.set({ url, name, value, expirationDate: Date.now() / 1000 + 120 })
const c1 = (await cookies.get({ url }))[0]
expect(c1.session).to.equal(false)

// 会话 Cookie:不传 expirationDate
await cookies.set({ url, name, value })
const c2 = (await cookies.get({ url }))[0]
expect(c2.session).to.equal(true)

6. cookies.remove(url, name):删除 Cookie

cookies.remove(url, name)

  • url string — 与 Cookie 关联的 URL。
  • name string — 要删除的 Cookie 名称。

返回 Promise<void>,Cookie 移除后解析。删除匹配 urlname 的 Cookie。

底层实现是构造 network::mojom::CookieDeletionFilter(仅含 urlcookie_name 两个字段)并调用 CookieManager::DeleteCookiesshell/browser/api/electron_api_cookies.cc#L342-L364),回调中的删除计数被忽略——只要调用成功 Promise 就解析。实践中常见的清理套路与测试里的 afterEach 钩子一致:先 get({ url }) 列出目标 URL 的全部 Cookie,再逐个 remove,保证测试或会话重置后存储干净。删除动作也会经 changed 事件以 cause: 'explicit'removed: true 的形式通知监听者。

7. cookies.flushStore():强制 Cookie 落盘

cookies.flushStore()

返回 Promise<void>,Cookie 存储完成写入后解析。

将尚未写盘的 Cookie 数据写入磁盘。需要理解其必要性:任何方法写入的 Cookie 都不会立即落盘,而是每 30 秒或每 512 次操作批量写入一次。调用 flushStore 可让当前 Cookie 立即写盘,典型场景包括应用退出前保存状态、或需要在磁盘层(备份、迁移)确认可见时。实现上它直接调用 CookieManager::FlushCookieStore 并在完成回调中解析 Promise(shell/browser/api/electron_api_cookies.cc#L443-L454)。

8. 小结与延伸阅读

  • Cookies 挂在 Session 上(session.cookies / session.defaultSession.cookies),按会话(分区)隔离,全部方法返回 Promise,适合 async/await 风格组织;
  • 查询用 get(filter) 组合 urldomainnamepathsecuresessionhttpOnly 过滤;写入用 set(details) 时注意 url 必填、sameSite 默认 laxno_restriction 隐含 secure: true
  • 需要感知 Cookie 增删改(含过期、逐出、覆盖)时监听 changed 事件,用 cause 区分八种变更原因、用 removed 判断是否删除;
  • 关心磁盘持久化时机时在关键节点调用 flushStore

相关文档与代码:Session APICookie 结构API 术语表(Main Process 等概念)、Cookies C++ 实现Cookie 变更通知器会话/Cookie 测试

登录后查看全文
热门项目推荐
相关项目推荐