外观
Cookie、localStorage、sessionStorage 怎么选?
会随请求发给服务器、或者要被服务端读写的会话,用 Cookie。只在浏览器里保存的偏好和缓存,用 localStorage。只在当前标签页有效的临时数据,用 sessionStorage。体积大、要索引的结构化数据用 IndexedDB。
原理
| Cookie | localStorage | sessionStorage | |
|---|---|---|---|
| 容量 | 约 4KB | 通常约 5MB | 通常约 5MB |
| 生命周期 | Expires / Max-Age,没有则会话结束 | 一直在,除非代码或用户清掉 | 标签页关闭为止 |
| 是否随请求发送 | 同源请求会带上 | 不会 | 不会 |
| API | 请求头,或 document.cookie | 同步的 getItem / setItem | 同步,按标签页隔离 |
| 范围 | 可按域和路径限制 | 同源共享 | 同源,而且每个标签页一份 |
Cookie 还能加限制:HttpOnly 使脚本读不到,Secure 只在 HTTPS 发送,SameSite 限制跨站是否携带。会话标识应该放在 HttpOnly Cookie 里,不要放进 localStorage,否则 XSS 可以直接读走。
localStorage 的读写是同步的,大字符串会卡住主线程。它只能存字符串,对象要自己 JSON.stringify。存储按源隔离:协议、域名、端口都相同才共享。
IndexedDB 是异步的事务数据库,适合离线数据和较大的结构化缓存。配合 Service Worker 的 Cache Storage 用来缓存请求和响应。
追问
标签页之间怎么同步?
localStorage 的写入会触发其他标签页的 storage 事件,当前页自己不会收到。只在内存里通信可以用 BroadcastChannel。
会话放 localStorage 还是 Cookie?
需要浏览器自动带上、并且脚本不该读取的令牌,放 HttpOnly + Secure + SameSite 的 Cookie。前端要主动塞进 Authorization 头的令牌,才考虑内存或 sessionStorage,并接受 XSS 能读到 sessionStorage 这个风险。
易错点
sessionStorage不是「会话 Cookie」。它按标签页隔离,复制出来的新标签不一定共享同一份数据。- Cookie 会进请求头,放大体积会拖慢每个请求。
localStorage满了,setItem会抛错,要自己捕获。