news 2026/9/7 4:22:06

Electron Cookie 对象结构详解:字段语义、源码实现与 Session Cookie API 实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Electron Cookie 对象结构详解:字段语义、源码实现与 Session Cookie API 实战

Electron Cookie 对象结构详解:字段语义、源码实现与 Session Cookie API 实战

【免费下载链接】electron:electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS项目地址: https://gitcode.com/GitHub_Trending/el/electron

本文以 Electron 的Cookie结构对象为核心,完整讲解其 10 个字段的语义、默认值与取值边界,并结合 shell/browser/api/electron_api_cookies.cc 的 C++ 实现,说明每个字段是如何从 Chromium 的CanonicalCookie转换而来、cookies.set()失败时底层如何诊断错误,以及如何在Sessionnet.request中正确读取、写入和监听 Cookie 变更。读完后你可以掌握:基于 Cookie 结构文档 编写可运行的 Cookie 读写代码,并理解sameSitehostOnlysessionexpirationDate等字段在源码层面的真实判定逻辑。

Cookie 对象字段总览

Cookie是 Electron 网络栈中统一的数据结构,由 docs/api/structures/cookie.md 定义。它是session.cookies.get()的返回元素,也是cookies实例changed事件的参数。字段完整列表如下:

字段类型必填说明
namestringCookie 的名称
valuestringCookie 的值
domainstring可选Cookie 的域名;会被规范化为带前导点(.)的形式,使其同样对子域名生效
hostOnlyboolean可选是否为 host-only cookie;仅当设置时未传入domain才为true
pathstring可选Cookie 的路径
secureboolean可选是否标记为 Secure(仅 HTTPS 传输)
httpOnlyboolean可选是否标记为 HttpOnly(JS 不可访问)
sessionboolean可选是会话 Cookie 还是带过期时间的持久 Cookie
expirationDateDouble可选过期时间,UNIX 时间戳(秒);会话 Cookie 不提供该字段
sameSitestringSameSite 策略,取值unspecifiedno_restrictionlaxstrict

一个服务端通过Set-Cookie写入的典型返回示例(来自 spec/api-net-session-spec.ts 中的真实断言,该测试对cookies.get({})的结果做了逐字段deep.equal校验):

{ name: 'foo', value: 'bar', domain: '127.0.0.1', // 未显式传 domain,因此为 host-only hostOnly: true, path: '/', secure: false, httpOnly: false, session: true, // 未设置 expirationDate,即会话 Cookie sameSite: 'unspecified' }

注意expirationDatesession: true时不存在,这正是文档中“会话 Cookie 不提供该字段”的体现。

字段是如何从 C++ 侧生成的:CanonicalCookie转换器

Electron 的Cookie对象并不是凭空拼装的 JSON,而是由 gin 框架把 Chromium 网络库的net::CanonicalCookie逐字段转换而来。在 shell/browser/api/electron_api_cookies.cc 中可以看到Converter<net::CanonicalCookie>的完整映射:

template <> struct Converter<net::CanonicalCookie> { static v8::Local<v8::Value> ToV8(v8::Isolate* isolate, const net::CanonicalCookie& val) { gin::Dictionary dict(isolate, v8::Object::New(isolate)); dict.Set("name", val.Name()); dict.Set("value", val.Value()); dict.Set("domain", val.Domain()); dict.Set("hostOnly", net::cookie_util::DomainIsHostOnly(val.Domain())); dict.Set("path", val.Path()); dict.Set("secure", val.SecureAttribute()); dict.Set("httpOnly", val.IsHttpOnly()); dict.Set("session", !val.IsPersistent()); if (val.IsPersistent()) dict.Set("expirationDate", val.ExpiryDate().InSecondsFSinceUnixEpoch()); dict.Set("sameSite", val.SameSite()); return ConvertToV8(isolate, dict).As<v8::Object>(); } };

从这段源码可以确认三件对理解文档语义很关键的事:

  1. hostOnly不是存储的字段,而是推导值。它调用net::cookie_util::DomainIsHostOnly(val.Domain())根据域名形式判断。这与文档“仅当设置时未传入domain才为true”的说法一致:设置 Cookie 时不给domain,底层就会按 host-only 存储,读回来时DomainIsHostOnly返回true
  2. sessionexpirationDate是互斥呈现的session直接取!val.IsPersistent(),只有IsPersistent()为真时才写入expirationDate,且取ExpiryDate().InSecondsFSinceUnixEpoch()——这解释了为什么文档强调expirationDate的单位是 UNIX 时间戳的秒。
  3. sameSite枚举到字符串的映射位于同文件的 Converternet::CookieSameSite:UNSPECIFIED -> "unspecified"NO_RESTRICTION -> "no_restriction"LAX_MODE -> "lax"STRICT_MODE -> "strict"。这就是文档中sameSite四个取值的来源,写死在转换层,不会出现第五种合法值。

通过 Session 读写 Cookie 的完整实战

Cookie对象由主进程 Cookies 类 产出。该类不从'electron'模块直接导出,只能通过Session实例的cookies属性访问。Electron 侧的绑定见 shell/browser/api/electron_api_session.cc 中Session::Cookies(isolate)的实现(以cppgc::Member<api::Cookies>成员持有)。

查询:session.cookies.get(filter)

完整示例(继承自 docs/api/cookies.md):

const { session } = require('electron') // 查询该 session 下的所有 cookie session.defaultSession.cookies.get({}) .then((cookies) => { console.log(cookies) // Cookie[] }).catch((error) => { console.log(error) }) // 只查询与特定 URL 关联的 cookie session.defaultSession.cookies.get({ url: 'https://www.github.com' }) .then((cookies) => console.log(cookies)) .catch((error) => console.log(error))

filter支持以下字段:

字段类型行为
urlstring (可选)只取与该 URL 关联的 cookie;省略或为空表示取全部
namestring (可选)按名称精确过滤
domainstring (可选)取域名匹配或其子域名的 cookie
pathstring (可选)按路径精确过滤
secureboolean (可选)按 Secure 属性过滤
sessionboolean (可选)区分会话 Cookie 与持久 Cookie
httpOnlyboolean (可选)按 HttpOnly 过滤

底层实现在 Cookies::Get:url为空时走manager->GetAllCookies();带url时构造net::CookieOptions(显式set_include_httponly()MakeInclusive()的 SameSite 上下文、set_do_not_update_access_time())后调用GetCookieList(),因此按 URL 查询能看到 HttpOnly Cookie 且不会刷新访问时间戳。随后的字段级过滤由 MatchesCookie 完成,它逐字段比对namepathdomain(用cookie.IsDomainMatch支持子域匹配)、securesessionhttpOnly

几个容易被忽视的行为细节:

  • session过滤的方向性:源码中判断为*session_filter == cookie.IsPersistent()则剔除,即session: true只保留会话 Cookie,session: false只保留持久 Cookie。spec/api-net-session-spec.ts 中“should be able correctly filter out cookies that are session”用例分别设置了不带和带expirationDate的两枚 Cookie,验证了双向过滤各得一条。
  • domain匹配支持子域IsDomainMatch意味着domain: 'example.com'能匹配.example.com下的 Cookie。
  • 无效域名的 set 会精确报错:测试用例验证了传入domain: 'wssss.iamabaddomain.fun'时 Promise 以 “The cookie was set with an invalid Domain attribute” 拒绝,该错误文案同样来自下文的InclusionStatusToString表。

写入:session.cookies.set(details)

// 设置 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) })

details参数与默认值(结合 docs/api/cookies.md 与源码实现):

字段类型默认值 / 说明
urlstring必填,Cookie 关联的 URL;URL 无效时 Promise 被拒绝
namestring (可选)省略时为空
valuestring (可选)省略时为空
domainstring (可选)省略时为空,此时生成 host-only Cookie
pathstring (可选)省略时为空
secureboolean (可选)默认false除非使用SameSite=None,此时强制为true
httpOnlyboolean (可选)默认false
expirationDateDouble (可选)UNIX 秒;省略则成为会话 Cookie,不跨会话保留
sameSitestring (可选)unspecified/no_restriction/lax/strict,默认lax

Cookies::Set 中的源码细节印证并补充了文档:

  • secure的强制逻辑bool secure = details.FindBool("secure").value_or(same_site == net::CookieSameSite::NO_RESTRICTION);—— 与文档“默认 false 除非 SameSite=None”完全对应,这是由SameSite=None必须 Secure 的规范要求驱动的。
  • sameSite解析:StringToCookieSameSite 在未传值时回退为LAX_MODE(即文档所说的默认lax),传入非法值时 Promise 以Failed to convert '...' to an appropriate cookie same site value拒绝。
  • url缺失与 URL 无效:缺url拒绝Missing required option 'url'GURL解析失败时按EXCLUDE_INVALID_DOMAIN构造状态串后拒绝。
  • 失败诊断表:InclusionStatusToString 维护了一张完整的排除原因表(EXCLUDE_INVALID_DOMAINEXCLUDE_SAMESITE_NONE_INSECUREEXCLUDE_DOMAIN_NON_ASCIIEXCLUDE_OVERWRITE_SECURE等 30 余种),当CanonicalCookie::CreateSanitizedCookie产出的 Cookie 非 canonical、或SetCanonicalCookie返回非 Include 状态时,Promise 会以 “Failed to set cookie - ...” 开头的可读文案拒绝。排查set()失败时可直接对照这张表定位原因。
  • 可选时间参数:实现中还读取了creationDatelastAccessDate(经 ParseTimeProperty 解析,0映射为 UNIX 纪元),当前 docs/api/cookies.md 的set()文档中仅列出expirationDate,阅读源码时留意这一差异。

删除与落盘:remove()flushStore()

// 移除匹配 url 与 name 的 cookie session.defaultSession.cookies.remove('https://www.github.com', 'dummy_name') .then(() => console.log('removed')) // 立即把内存中的 cookie 写入磁盘 session.defaultSession.cookies.flushStore() .then(() => console.log('flushed'))
  • remove(url, name)在 Cookies::Remove 中构造network::mojom::CookieDeletionFilter并调用DeleteCookies(),回调携带被删除数量(num_deleted)但 API 层不暴露该值。
  • flushStore()对应FlushCookieStore()。文档指出:任何方法写入的 Cookie 不会立即落盘,而是每 30 秒或每 512 次操作写盘一次;在应用退出前调用flushStore()可避免持久 Cookie 丢失。

监听变更:changed事件与 cause 语义

cookies实例支持changed事件(docs/api/cookies.md),回调参数为(event, cookie, cause, removed),其中cookie就是一个Cookie结构对象。cause的八个取值及其含义:

cause含义
insertedCookie 被插入
inserted-no-change-overwrite新插入的 Cookie 覆盖了旧值但未产生变化(如插入完全相同的 Cookie)
inserted-no-value-change-overwrite覆盖写入且值未变,但对 Web 可观测(例如更新了过期时间)
explicit被使用者操作直接删除
overwrite因插入操作覆盖而被自动移除
expired因过期被自动移除
evicted垃圾回收时被自动驱逐
expired-overwrite被一个已过期的时间戳覆盖

这些字符串与 Chromium 的net::CookieChangeCause枚举一一对应,映射代码见 Converternet::CookieChangeCause。事件的分发链路是:Cookies构造时向browser_context_->cookie_change_notifier()注册回调(electron_api_cookies.cc L300-L306),每次变更触发 Cookies::OnCookieChanged,其中removed布尔值由 IsDeletion 判定——三种INSERTED_*视为未删除,其余一律视为删除。典型用途如会话同步、登出时清理、持久化登录态:

const { session } = require('electron') session.defaultSession.cookies.on('changed', (_event, cookie, cause, removed) => { if (removed) { console.log(`cookie ${cookie.name} removed, cause: ${cause}`) } else { console.log(`cookie ${cookie.name}=${cookie.value} changed, cause: ${cause}`) } })

Cookie 存储与net.request的联动

理解Cookie结构后,一个高频实战场景是主进程net模块复用会话 Cookie 存储。spec/api-net-session-spec.ts 用测试锁定了几个关键行为:

  1. 默认不附带 Cookienet.request({ url, session })默认不使用该 session 的 Cookie 存储(测试断言服务端收到的 Cookie 为undefined)。
  2. 开启方式:传{ credentials: 'include' }{ useSessionCookies: true }后,cookies.set()写入的 Cookie 会随请求自动附带,服务端能收到wild_cookie=<value>
  3. session.fetch同理sess.fetch(serverUrl, { credentials: 'include' })会带上存储中的 Cookie。
  4. SameSite 与重定向安全:测试“safely across redirects”表明,lax/strictCookie 在跨站重定向后不会跟随,只有no_restriction才会;且重定向到新域后,存储层会自动改为附带新目标域的 Cookie——这正是sameSite字段在结构层设计存在的意义。
  5. 手动覆盖:即使启用了会话 Cookie,request.setHeader('Cookie', ...)仍可整体覆盖 Cookie 头(测试“should be able to set cookie header line”)。

小结

Cookie结构是 Electron 网络能力的数据基石:字段语义由 docs/api/structures/cookie.md 定义,实际值由 electron_api_cookies.cc 中的CanonicalCookie转换器逐字段生成,读取过滤、写入校验、变更事件与落盘策略均有对应的 C++ 实现与 spec/api-net-session-spec.ts 的测试用例佐证。掌握这张“文档—源码—测试”三对照表后,无论是实现自动登录、Cookie 同步还是网络诊断,都可以在这套结构上可靠地构建功能。相关延伸文档:Cookies 类、Session 类、net 模块。

【免费下载链接】electron:electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS项目地址: https://gitcode.com/GitHub_Trending/el/electron

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/7 4:20:58

Minecraft 1.21.11离线服务器搭建教程:域名联机全攻略

自己开一个 Minecraft 服务器邀请朋友联机&#xff0c;最常见的一个需求就是“离线可进”。这意味着朋友不一定都购买了正版 Minecraft&#xff0c;或者客户端启动器没有登录正版账号&#xff0c;而服务器也不用向 Mojang 的鉴权服务器验证玩家身份。本文以题目给出的 1.21.11 …

作者头像 李华
网站建设 2026/9/7 4:18:51

YOLOv8结构拆解与改进实战:从数据诊断到消融实验

做毕业设计选 YOLOv8&#xff0c;是目前很多同学的目标检测标配。但一个常见的现象是&#xff1a;代码下载很顺利&#xff0c;训练完一看 mAP&#xff0c;效果并不理想。于是很多人开始在网上搜索各种改进模块&#xff0c;注意力机制、小目标检测头、BiFPN、新损失函数……一样…

作者头像 李华