Cookie Store API 是什么?
Cookie Store API 会将 HTTP Cookie 公开给服务工件,并提供 document.cookie
的异步替代方案。借助此 API,您可以更轻松地:
- 通过异步访问 Cookie,避免主线程卡顿。
- 避免轮询 Cookie,因为可以观察 Cookie 的更改。
- 从服务工件访问 Cookie。
当前状态
步骤 | 状态 |
---|---|
1. 创建铺垫消息 | 完成 |
2. 创建规范的初始草稿 | 完成 |
**3. 收集反馈并迭代规范** | **进行中** |
4. 来源试用 | 已暂停 |
5. 发布 | 尚未开始 |
如何使用异步 Cookie 存储区?
启用来源试用
如需在本地试用,您可以在命令行上启用该 API:
chrome --enable-blink-features=CookieStore
在命令行中传递此标志可在 Chrome 中为当前会话全局启用该 API。
或者,您也可以在 chrome://flags
中启用 #enable-experimental-web-platform-features
标志。
您(可能)不需要 Cookie
在深入了解新 API 之前,我想先说明一点,Cookie 仍然是 Web 平台最糟糕的客户端存储基元,应仅作为最后的手段使用。这并非偶然 - Cookie 是 Web 的第一个客户端存储机制,我们从中学到了很多。
避免使用 Cookie 的主要原因如下:
Cookie 可将存储架构引入到后端 API。 每个 HTTP 请求都携带 Cookie Jar 的快照。这样,后端工程师就可以轻松引入对当前 Cookie 格式的依赖项。发生这种情况后,前端将无法更改其存储架构,除非将相应的更改部署到后端。
Cookie 采用复杂的安全模型。现代 Web 平台功能遵循相同的源政策,这意味着每个应用都会获得自己的沙盒,并且完全独立于用户可能正在运行的其他应用。Cookie 作用域会导致安全问题变得更加复杂,仅仅尝试对其进行总结,本文的篇幅就会翻倍。
Cookie 的性能开销很高。浏览器需要在每个 HTTP 请求中包含 Cookie 的快照,因此对 Cookie 的每项更改都必须传播到存储空间和网络堆栈。现代浏览器采用了高度优化的 Cookie 存储区实现,但我们永远无法使 Cookie 的效率与其他无需与网络堆栈通信的存储机制一样高。
出于上述所有原因,现代 Web 应用应避免使用 Cookie,而应将会话标识符存储到 IndexedDB,并通过 fetch API 将标识符明确添加到特定 HTTP 请求的标头或正文中。
尽管如此,您之所以仍在阅读本文,是因为您有充分的理由使用 Cookie...
读取 Cookie 并消除卡顿
久经考验的 document.cookie API 是导致应用卡顿的相当可靠的来源。例如,每当您使用 document.cookie
Getter 时,浏览器都必须停止执行 JavaScript,直到获得您请求的 Cookie 信息。这可能需要进行进程跳转或磁盘读取,并会导致界面卡顿。
解决此问题的简单方法是从 document.cookie
Getter 切换到异步 Cookie 存储 API。
await cookieStore.get('session_id');
// {
// domain: "example.com",
// expires: 1593745721000,
// name: "session_id",
// path: "/",
// sameSite: "unrestricted",
// secure: true,
// value: "yxlgco2xtqb.ly25tv3tkb8"
// }
document.cookie
Setter 也可以以类似的方式替换。请注意,只有在 cookieStore.set
返回的 Promise 解析后,更改才保证会应用。
await cookieStore.set({name: 'opt_out', value: '1'});
// undefined
观察,不要轮询
从 JavaScript 访问 Cookie 的一种常见应用是检测用户何时退出并更新界面。目前,这通过轮询 document.cookie
来实现,这会导致卡顿并对电池续航时间产生负面影响。
Cookie Store API 提供了一种观察 Cookie 更改的替代方法,无需轮询。
cookieStore.addEventListener('change', event => {
for (const cookie of event.changed) {
if (cookie.name === 'session_id') sessionCookieChanged(cookie.value);
}
for (const cookie of event.deleted) {
if (cookie.name === 'session_id') sessionCookieChanged(null);
}
});
欢迎使用 Service Worker
由于采用同步设计,document.cookie
API 尚未向服务工件提供。Cookie Store API 是异步的,因此可以在服务工作器中使用。
在文档上下文和服务工件中与 Cookie 互动的方式相同。
// Works in documents and service workers.
async function logOut() {
await cookieStore.delete('session_id');
}
不过,在 Service Worker 中监控 Cookie 更改的方式略有不同。唤醒服务工作器的开销可能非常高,因此我们必须明确说明该工作器感兴趣的 Cookie 更改。
在以下示例中,使用 IndexedDB 缓存用户数据的应用会监控会话 Cookie 的更改,并在用户退出登录时舍弃缓存的数据。
// Specify the cookie changes we're interested in during the install event.
self.addEventListener('install', event => {
event.waitUntil(cookieStore.subscribeToChanges([{name: 'session_id'}]));
});
// Delete cached data when the user logs out.
self.addEventListener('cookiechange', event => {
for (const cookie of event.deleted) {
if (cookie.name === 'session_id') {
indexedDB.deleteDatabase('user_cache');
break;
}
}
});
最佳做法
即将推出。
反馈
如果您试用此 API,请告诉我们您的想法!请将有关 API 形状的反馈发送到规范代码库,并将实现 bug 报告给 Blink>Storage>CookiesAPI
Blink 组件。
我们特别希望了解说明文档中未提及的效果衡量和用例。
其他资源
- 公开说明文
- 规格
- 跟踪 bug
- chromestatus.com 条目
- WICG Discourse 会话
- 闪烁组件:
Blink>Storage>CookiesAPI