浏览器存储详解

1. 核心存储方式对比

特性CookielocalStoragesessionStorageIndexedDB
容量限制极小 (4KB)大 (~5MB)大 (~5MB)极大 (>50MB)
生命周期可设置过期时间,不设则为会话级永久有效 (除非手动清除)会话级 (Tab 关闭即销毁)永久有效
服务器通信每次 HTTP 请求自动携带不参与通信不参与通信不参与通信
访问权限同源同源同源同源
安全性可设 HttpOnly 防 XSS易受 XSS易受 XSS同源策略保护
API 易用性难用 (需正则封装)简单 (setItem/getItem)简单 (setItem/getItem)复杂 (异步事务)

2. 深度解析

最古老的机制,设计初衷是维持 HTTP 状态 (Session ID) 而非存储数据。

关键属性 (面试题)

  • HttpOnly: 禁止 JavaScript 访问 (document.cookie),防止 XSS 攻击窃取 Token。
  • Secure: 仅在 HTTPS 传输。
  • SameSite: 防止 CSRF 攻击 (Strict, Lax, None)。
    • Strict: 禁止第三方请求携带。
    • Lax (默认): 允许安全的顶级导航 (如链接跳转) 携带。

缺陷

  • 性能损耗:由于每次请求都会带上 Cookie,如果存了几 KB 无关数据,会严重浪费带宽。
  • 容量太小:仅 4KB。

(2) localStorage

适合场景:长期保存的非敏感数据。

  • 用户偏好设置 (Theme, Language)。
  • 简单的应用状态持久化。
  • 长效缓存 (如静态数据字典)。

注意

  • 虽大但有限:5MB 满了会报错 (QuotaExceededError),需 try-catch。
  • 同步阻塞:读写操作是同步的,读写大数据会阻塞主线程。

(3) sessionStorage

适合场景:单次会话的临时数据。

  • 表单分步填写数据 (防止刷新丢失)。
  • 一次性登录状态 (如某些后台管理系统)。

面试题新开标签页 sessionStorage 会共享吗?

  • 不会。sessionStorage 是基于 Top-Level Browsing Context 的,即使同源,不同 Tab 也是隔离的。
  • 特例:通过 window.open<a target="_blank"> 打开的新标签页,在某些浏览器 (如 Chrome) 会复制旧页面的 sessionStorage,但之后互不影响。

(4) IndexedDB

浏览器内置的非关系型数据库 (NoSQL)。

特点

  • 异步:读写不会阻塞主线程。
  • 支持二进制:可直接存 ArrayBuffer, Blob (图片/文件)。
  • 事务:支持 ACID。
  • 索引:支持高性能查询。

场景

  • 离线应用 (PWA) 的大量数据存储。
  • 编辑器应用 (如 VSCode Web) 缓存文件内容。

3. 安全性最佳实践

Q: Token 应该存在哪?

这是一个经典的面试争论题。

  • 方案 A (localStorage):

    • 优点:简单,前端控制力强,方便加到 Header (Authorization: Bearer ...)。
    • 缺点:容易被 XSS 攻击窃取 (一个 localStorage.getItem 就偷走了)。需配合严谨的 XSS 防御。
  • 方案 B (HttpOnly Cookie):

    • 优点:JS 无法读取,天然免疫 XSS 窃取。
    • 缺点:容易被 CSRF 攻击 (跨站伪造请求)。需配合 CSRF Token 或 SameSite 属性。
    • 推荐:对于高安全性要求,使用 HttpOnly Cookie + CSRF Token 是业界标准。

Q: 如何手动实现 localStorage 过期?

原生不支持。封装时存入 { value, expire: Date.now() + 1000 }。读取时判断 Date.now() > expire,如果超时则 removeItem 并返回 null。