返回博客

localStorage、sessionStorage、Cookie:什么时候用哪个

浏览器存储机制的实战对比,包含代码示例和构建 Web 工具时的真实使用场景。

三种在浏览器里存数据的方式,它们都不一样

每个 Web 开发者迟早会碰到同一个问题:把数据存在哪里才能让页面刷新后还在?浏览器给了你三个主要选项,选错了会导致那种很难追踪的 bug。

localStorage、sessionStorage 和 Cookie 都在浏览器里存数据,但它们在生命周期、容量和是否发送到服务器方面行为不同。搞清楚这些区别,能让你避免经典错误:把用户偏好存在 Cookie 里然后纳闷为什么一个月后消失了,或者把一个大 JSON 塞进 Cookie 然后看着请求体积膨胀。

localStorage 会一直存在直到你手动清除

localStorage 是一个键值对存储,跨浏览器会话持久化。你关掉标签页、关掉浏览器、重启电脑,数据回来时还在。每个源的存储上限通常是 5-10 MB,对于配置、历史记录和小数据集来说绰绰有余。

// 保存一个值
localStorage.setItem("theme", "dark");

// 读取
const theme = localStorage.getItem("theme");

// 删除
localStorage.removeItem("theme");

// 清除这个源下的所有数据
localStorage.clear();

API 是同步的,很简单。你存的是字符串,取回来的也是字符串。如果你需要存对象,用 JSON.stringify() 序列化,再用 JSON.parse() 解析回来。

const history = [
  { url: "https://example.com/stream.m3u8", date: "2026-06-23" },
  { url: "https://example.com/live.m3u8", date: "2026-06-22" },
];
localStorage.setItem("playbackHistory", JSON.stringify(history));

在 Anoiona Tools,我们用 localStorage 存储 M3U8 播放器的播放历史、主题偏好和语言选择。这些东西应该在多次访问之间保留,但不需要跨设备同步。

有一点需要注意:localStorage 是同步阻塞的。如果你往里面写大量数据,主线程会暂停。大多数场景下感觉不到,但如果你存了几 MB 的数据,可能会出现明显的卡顿。

sessionStorage 在标签页关闭时就没了

sessionStorage 的工作方式和 localStorage 类似,但有一个关键区别:它的作用域是当前标签页,标签页关闭就清除。在两个标签页打开同一个网站,每个标签页有自己独立的 sessionStorage。

sessionStorage.setItem("currentStep", "3");
// 刷新页面,值还在
// 关闭标签页,值就没了

这让 sessionStorage 适合多步表单、向导流程或者不应该持久化的临时状态。如果用户开始填表单,不小心关了标签页再回来,他们会从头开始,而不是看到一个令人困惑的半填状态。

sessionStorage 的存储上限和 API 与 localStorage 完全一样。唯一的区别是生命周期和每个标签页的隔离性。

大多数开发者默认就用 localStorage,忘了 sessionStorage 的存在。值得想一想你的数据是否真的需要在标签页关闭后保留。如果不需要,sessionStorage 是更干净的选择,因为它不会随时间累积。

Cookie 和 localStorage、sessionStorage 有本质区别,因为它会在每个 HTTP 请求中自动发送给服务器。这是它的主要用途:让服务器知道客户端的一些信息。

// 设置一个 7 天后过期的 Cookie
document.cookie = "session=abc123; max-age=604800; path=/; SameSite=Lax";

Cookie 的存储上限小得多,通常每个 Cookie 约 4 KB。它可以设置过期时间、路径、域名,以及 HttpOnlySecureSameSite 等安全标志。

HttpOnly 标志特别重要:它阻止 JavaScript 读取 Cookie,从而防止跨站脚本攻击。认证令牌几乎都应该设为 HttpOnly Cookie。

Set-Cookie: token=xyz789; HttpOnly; Secure; SameSite=Strict; Path=/

对于会话管理和认证,Cookie 是正确的工具。服务器设置 Cookie,浏览器在每个请求中把它带回去。服务器可以验证会话,完全不需要 JavaScript 介入。

对于服务器不需要知道的客户端状态,Cookie 是错误的工具。你设置的每个 Cookie 都会增加发往该域名的每个 HTTP 请求的体积。如果你把一个 3 KB 的 JSON 存在 Cookie 里,那个页面上的每个图片、样式表和 API 调用都会在请求头里携带这 3 KB。

快速决策指南

localStorage 的场景:

  • 数据需要跨浏览器会话保留。
  • 数据只有 JavaScript 需要,服务器不需要。
  • 你需要超过 4 KB 的存储空间。
  • 例子:用户偏好、播放历史、草稿内容。

sessionStorage 的场景:

  • 数据只需要在当前标签页会话中存在。
  • 你需要标签页之间的隔离。
  • 例子:表单状态、临时筛选条件、向导进度。

Cookie 的场景:

  • 服务器需要在每个请求中获取这个数据。
  • 你存的是认证令牌或会话标识。
  • 数据很小(4 KB 以下)。
  • 例子:会话 ID、CSRF 令牌、发送给服务器的语言偏好。

不要用 Cookie 存大的客户端数据。不要用 localStorage 存需要 HttpOnly 保护的认证令牌。不要用 sessionStorage 存需要在浏览器重启后保留的数据。

storage 事件和跨标签页通信

localStorage 有一个经常被忽略的特性:storage 事件。当一个标签页修改了 localStorage 的值,同一个源下的其他标签页会收到事件。这可以用来在标签页间同步状态,不需要服务器。

window.addEventListener("storage", (event) => {
  if (event.key === "theme") {
    applyTheme(event.newValue);
  }
});

sessionStorage 不会触发这个事件,因为每个标签页有自己独立的存储。Cookie 也不会触发,虽然你可以通过轮询来检测 Cookie 变化。

这个跨标签页行为既实用又容易踩坑。如果你在一个标签页里改了值,期望其他标签页看不到这个变化,那 localStorage 就选错了。用 sessionStorage 或者更受限的状态管理方案。

清除存储是用户的权利

浏览器允许用户在设置里清除网站数据。用户可以针对某个网站或所有网站清除 localStorage、sessionStorage、Cookie、IndexedDB 和缓存文件。这意味着你的应用应该能优雅地处理存储缺失。

如果你读 localStorage 发现值没了,回退到默认值。如果 sessionStorage 为空是因为用户开了新标签页,不要崩溃。存储是便利,不是保证。

有些浏览器还会在一段时间不活跃后自动清除网站数据。Safari 在这方面特别激进。如果你的应用依赖 localStorage 存储关键状态,考虑一下这些状态在存储被清除后能否重建。