测验

描述浏览器中 cookie、`sessionStorage` 和 `localStorage` 之间的区别

主题
Web APIJavaScript

总结

以下都是在客户端(本例中为用户的浏览器)上存储数据的机制。localStorage 和 sessionStorage 都实现了 Web Storage API 接口。

  • Cookies:适用于服务器-客户端通信,存储容量小,可以是持久性的或基于会话的,特定于域。在每次请求时发送到服务器。
  • localStorage:适用于长期存储,即使在浏览器关闭后数据仍然存在,可在同一来源的所有选项卡和窗口中访问,在三者中存储容量最高。
  • sessionStorage:适用于单个页面会话中的临时数据,当选项卡或窗口关闭时数据将被清除,与 cookies 相比具有更高的存储容量。

以下表格总结了 3 种客户端存储机制。

属性CookielocalStoragesessionStorage
发起者客户端或服务器。服务器可以使用 Set-Cookie 标头客户端客户端
寿命如指定直到删除直到选项卡关闭
是否跨浏览器会话持久如果设置了未来的过期日期是否
是否随每个 HTTP 请求发送到服务器是,通过 Cookie 标头发送否否
典型存储限制每个 cookie 约 4 KB每个来源约 5 MB(因浏览器而异)每个来源约 5 MB(因浏览器而异)
访问跨窗口/选项卡跨窗口/选项卡相同选项卡
安全性JavaScript 无法访问 HttpOnly cookies无无

Web 上的存储

Cookies、localStorage 和 sessionStorage 都是客户端(Web 浏览器)上的存储机制。在客户端存储数据对于仅客户端的状态很有用,例如访问令牌、主题、个性化布局,以便用户可以在跨选项卡和使用会话的网站上获得一致的体验。

这些客户端存储机制具有以下常见属性:

  • 这意味着客户端可以读取和修改值(HttpOnly cookies 除外)。
  • 基于键值对的存储。
  • 它们只能将值存储为字符串。非字符串必须被序列化为字符串(例如 JSON.stringify())才能被存储。

每种存储机制的用例

由于 cookies 的最大大小相对较小,因此不建议将所有客户端数据存储在 cookies 中。关于 cookies 的显著特性是 cookies 会在每个 HTTP 请求中发送到服务器,因此较小的最大大小是一个特性,可以防止您的 HTTP 请求由于 cookies 而变得过大。cookies 的自动过期也是一个有用的特性。

考虑到这一点,最适合存储在 cookies 中的数据是需要传输到服务器的小块数据,例如身份验证令牌、会话 ID、分析跟踪 ID、GDPR cookie 同意、对身份验证、授权和在服务器上呈现很重要的语言偏好。这些值有时很敏感,并且可以从 cookies 提供的 HttpOnly、Secure 和 Expires/Max-Age 功能中受益。

localStorage 和 sessionStorage 都实现了 Web Storage API 接口。Web Storages 具有 5MB 的总容量,因此存储大小通常不是问题。关键的区别在于,存储在 Web Storage 中的值不会自动随 HTTP 请求一起发送。

虽然您可以在发出 AJAX/fetch() 请求时手动包含来自 Web Storage 的值,但浏览器不会在页面的初始请求/首次加载中包含它们。因此,如果使用服务器端渲染(通常是与身份验证/授权相关的信息),则不应使用 Web Storage 来存储服务器用于页面初始渲染所依赖的数据。localStorage 最适合不失效的用户偏好数据,例如主题和布局(如果服务器渲染最终布局并不重要)。sessionStorage 最适合只需要在当前浏览会话中访问的临时数据,例如表单数据(用于在意外重新加载期间保留数据)。

以下部分深入探讨了每种客户端存储机制。

Cookies

Cookies 用于在客户端存储小块数据,这些数据可以通过每个 HTTP 请求发送回服务器。

  • 存储容量:每个 cookie 限制在 4 KB 左右。浏览器还会限制每个域可存储的 cookie 数量。
  • 寿命:Cookies 可以使用 Expires 或 Max-Age 属性设置特定的过期日期。如果未设置过期日期,则在浏览器关闭时删除 cookie(会话 cookie)。
  • 访问:Cookies 是特定于域的,可以在同一域内的不同页面和子域之间共享。
  • 安全性:Cookies 可以标记为 HttpOnly 以防止从 JavaScript 访问,从而降低 XSS 攻击的风险。它们也可以使用 Secure 标志进行保护,以确保仅在使用 HTTPS 时发送它们。
// Set a cookie for the name/key `auth_token` with an expiry.
document.cookie =
'auth_token=abc123def; expires=Fri, 31 Dec 2024 23:59:59 GMT; path=/';
// Read all cookies. There's no way to read specific cookies using `document.cookie`.
// You have to parse the string yourself.
console.log(document.cookie); // auth_token=abc123def
// Delete the cookie with the name/key `auth_token` by setting an
// expiry date in the past. The value doesn't matter.
document.cookie = 'auth_token=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/';

读取/写入 Cookie 是一件很痛苦的事情。document.cookie 返回一个包含所有由 ; 分隔的键/值对的字符串,您必须自己解析该字符串。js-cookie npm 库提供了一个简单轻量级的 API,用于在 JavaScript 中读写 Cookie。

访问 Cookie 的现代原生方式是通过 Cookie Store API,该 API 仅在 HTTPS 页面上可用。

// Set a cookie. More options are available too.
cookieStore.set('auth_token', 'abc123def');
// Async method to access a single cookie and do something with it.
cookieStore.get('auth_token').then(...);
// Async method to get all cookies.
cookieStore.getAll().then(...);
// Async method to delete a single cookie.
cookieStore.delete('auth_token').then(() =>
console.log('Cookie deleted')
);

CookieStore API 相对较新,可能并非所有浏览器都支持(截至 2024 年 6 月,在最新的 Chrome 和 Edge 中受支持)。请参阅 caniuse.com 以获取最新的兼容性信息。

localStorage

localStorage 用于存储即使在浏览器关闭并重新打开后仍保留的数据。它专为长期存储数据而设计。

  • 存储容量:通常每个来源约 5MB(因浏览器而异)。
  • 生命周期:localStorage 中的数据会一直存在,直到用户或应用程序显式删除。
  • 访问:数据可在同一来源的所有选项卡和窗口中访问。
  • 安全性:页面上的所有 JavaScript 都可以访问 localStorage 中的值。
// Set a value in localStorage.
localStorage.setItem('key', 'value');
// Get a value from localStorage.
console.log(localStorage.getItem('key'));
// Remove a value from localStorage.
localStorage.removeItem('key');
// Clear all data in localStorage.
localStorage.clear();

sessionStorage

sessionStorage 用于存储页面会话期间的数据。它专为临时存储数据而设计。

  • 存储容量: 通常每个来源约 5MB(取决于浏览器)。
  • 生命周期: sessionStorage 中的数据在页面会话结束时清除(即,当浏览器或选项卡关闭时)。重新加载页面不会销毁 sessionStorage 中的数据。
  • 访问: 数据仅在当前选项卡(或浏览上下文)中可访问。不同的选项卡共享不同的 sessionStorage 对象,即使它们属于同一个浏览器窗口。在这种情况下,窗口指的是可以包含多个选项卡的浏览器窗口。
  • 安全性: 同一页面上的所有 JavaScript 都可以访问该页面 sessionStorage 中的值。
// Set a value in sessionStorage.
sessionStorage.setItem('key', 'value');
// Get a value from sessionStorage.
console.log(sessionStorage.getItem('key'));
// Remove a value from sessionStorage.
sessionStorage.removeItem('key');
// Clear all data in sessionStorage.
sessionStorage.clear();

注意事项

还有其他客户端存储机制,例如 IndexedDB,它比上述技术更强大,但使用起来更复杂。

参考

练习

检验你的理解
测试版
检验你的理解 练习 1/4
检验你的理解 练习 1/4

A checkout draft should survive reloads in the current tab, remain isolated from another tab on the same origin, and disappear when the tab closes. Which storage mechanism best matches those requirements?