FumadocsZDecode
浏览器

浏览器存储

一、总览对比

特性CookielocalStoragesessionStorageIndexedDB
容量~4 KB~5 MB~5 MB数百 MB+
生命周期可设过期时间永久(手动清除)标签页关闭即清除永久(手动清除)
随请求发送✅ 自动携带
跨标签页共享
跨域访问同域(可配 domain)❌ 同源❌ 同源❌ 同源
可被 JS 访问可(除 HttpOnly)
API 类型字符串拼接同步 Key-Value同步 Key-Value异步事务
适合存储会话凭证、偏好用户设置、缓存数据单次会话临时数据大量结构化数据

二、Cookie

HTTP 协议的一部分,每次请求自动携带,主要用于身份认证

// 读写(字符串操作,较繁琐)
document.cookie = 'token=abc123; path=/; max-age=3600; Secure; SameSite=Strict'
document.cookie // 只读出未被 HttpOnly 保护的 cookie

// 删除:把 max-age 设为 0
document.cookie = 'token=; max-age=0'

关键属性

属性作用
Expires / Max-Age过期时间,不设则为会话 cookie
HttpOnly禁止 JS 读取,防 XSS 窃取
Secure仅 HTTPS 发送
SameSite防 CSRF:Strict / Lax / None
Domain指定哪些域名可访问,默认当前域
Path指定哪些路径携带 cookie

三、localStorage

同源页面永久共享,适合持久化用户偏好、非敏感缓存

localStorage.setItem('theme', 'dark')
localStorage.getItem('theme')    // 'dark'
localStorage.removeItem('theme')
localStorage.clear()             // 清空所有
localStorage.length              // key 的数量
localStorage.key(0)              // 按下标取 key 名

只能存字符串,对象需序列化:

localStorage.setItem('user', JSON.stringify({ name: 'Tom' }))
const user = JSON.parse(localStorage.getItem('user'))

监听跨标签页变化:

window.addEventListener('storage', (e) => {
  console.log(e.key, e.oldValue, e.newValue)
  // 注意:当前标签页自己的修改不会触发此事件
})

四、sessionStorage

与 localStorage API 完全相同,区别在于标签页关闭即清除,且不跨标签页共享

sessionStorage.setItem('step', '2')
sessionStorage.getItem('step') // '2'

适合:多步骤表单中间状态、单次会话的临时数据。

刷新页面数据仍在,只有关闭标签页(或标签页跳转到新 origin)才清除。


五、IndexedDB

浏览器内置的 NoSQL 数据库,支持大容量、结构化数据、索引查询,API 全部异步。

const request = indexedDB.open('myDB', 1)

request.onupgradeneeded = (e) => {
  const db = e.target.result
  db.createObjectStore('users', { keyPath: 'id' })
}

request.onsuccess = (e) => {
  const db = e.target.result

  // 写入
  const tx = db.transaction('users', 'readwrite')
  tx.objectStore('users').add({ id: 1, name: 'Tom' })

  // 读取
  const getTx = db.transaction('users', 'readonly')
  getTx.objectStore('users').get(1).onsuccess = (e) => {
    console.log(e.target.result) // { id: 1, name: 'Tom' }
  }
}

适合:离线应用、大量数据缓存(图片 blob、日志、本地数据库)。实际使用通常借助 idb 等库简化 API。


六、Storage 接口

localStoragesessionStorage 都是 Storage 接口的实例,浏览器原生定义如下:

interface Storage {
  readonly length: number
  key(index: number): string | null
  getItem(key: string): string | null
  setItem(key: string, value: string): void
  removeItem(key: string): void
  clear(): void
}
  • length:当前存储了多少个 key
  • key(n):按下标返回 key 名,配合 length 可遍历所有条目
  • getItem / setItem / removeItem:增删改查
  • 值只能是字符串,传入非字符串会自动调用 .toString()
// localStorage 和 sessionStorage 是同一接口的两个不同实例
localStorage instanceof Storage   // true
sessionStorage instanceof Storage // true

// 遍历所有 key
for (let i = 0; i < localStorage.length; i++) {
  const key = localStorage.key(i)
  console.log(key, localStorage.getItem(key))
}

Storage 本身不可直接 new,是浏览器内部实现并挂载到 window 上的。你无法创建自己的 Storage 实例,只能使用 window.localStoragewindow.sessionStorage 这两个全局对象。


七、使用场景速查

场景推荐方案
登录 token(安全)HttpOnly Cookie
主题 / 语言偏好localStorage
多步骤表单草稿sessionStorage
购物车(跨标签页同步)localStorage + storage 事件
离线缓存 / 大文件IndexedDB
敏感数据(密码等)不要存在任何客户端存储中

On this page