一、核心特性对比表
| 特性/技术 | Cookie | localStorage | sessionStorage | IndexedDB | WebSQL (已废弃) |
|---|---|---|---|---|---|
| 出现时间 | 1993年 | 2009年 | 2009年 | 2015年 | 2009年 |
| 推动标准/公司 | 网景公司 (Lou Montulli) | HTML5规范 | HTML5规范 | W3C标准 | HTML5草案 |
| 技术背景 | 解决HTTP无状态问题,实现会话管理 | 解决Cookie容量小和性能问题 | 解决Cookie容量小和性能问题 | 替代WebSQL,支持非关系型数据和大容量存储 | 引入关系型数据库能力 |
| 最大容量 | 4KB | 5-10MB | 5-10MB | 50%磁盘空间 | 5-50MB |
| 生命周期 | 可设置过期时间 | 永久存储 | 标签页关闭清除 | 永久存储 | 永久存储 |
| 数据格式 | 字符串 | 字符串 | 字符串 | 结构化数据/二进制 | 关系型数据 |
| 服务器访问 | ✅ 每次请求自动携带 | ❌ | ❌ | ❌ | ❌ |
| 同源共享 | 全域名 | 全域名 | 单标签页 | 全域名 | 全域名 |
| 事务支持 | ❌ | ❌ | ❌ | ✅ | ✅ |
| 查询能力 | 键查找 | 键查找 | 键查找 | 高级索引查询 | SQL查询 |
| 异步操作 | ❌ | ❌ | ❌ | ✅ | ✅ |
| 浏览器支持 | 所有浏览器 | 所有现代浏览器 | 所有现代浏览器 | 所有现代浏览器 | 仅WebKit内核 |
| 标准状态 | 标准化 | HTML5标准 | HTML5标准 | W3C标准 | 已废弃 |
| 适用场景 | 会话管理/身份认证 | 用户偏好设置 | 表单草稿/临时状态 | 离线应用/大型数据 | 不应使用 |
二、详细技术解析
1. Cookie
核心特性:
- 容量限制:每个Cookie不超过4KB,每个域名下最多允许20-50个Cookie(取决于浏览器)
- 生命周期:可设置过期时间(
Expires或Max-Age),未设置则为会话Cookie(关闭浏览器即失效) - 作用域:通过
Domain和Path属性控制可见性 - 自动传输:每次HTTP请求都会自动携带同域Cookie,可通过
Secure(仅HTTPS)和HttpOnly(禁止JS访问)增强安全 - 同步API:通过
document.cookie读写,操作可能阻塞主线程
// 设置Cookie
document.cookie = "username=john_doe; expires=Fri, 31 Dec 2023 23:59:59 GMT; path=/";
// 读取Cookie
function getCookie(name) {
const cookies = document.cookie.split('; ');
for (const cookie of cookies) {
const [key, value] = cookie.split('=');
if (key === name) return decodeURIComponent(value);
}
return null;
}
// 删除Cookie
document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/";
最佳实践:
- 仅用于会话管理(如存储Session ID)
- 敏感数据设置
HttpOnly和Secure属性 - 使用
SameSite属性防御CSRF攻击(推荐Lax或Strict) - 避免存储大数据(影响请求性能)
2. localStorage
核心特性:
- 持久存储:数据永久保存,除非主动清除
- 同源策略:相同协议+域名+端口共享数据
- 同步API:可能阻塞主线程
- 存储格式:仅字符串(需序列化对象)
- 容量:5-10MB(不同浏览器有差异)
// 基础操作
localStorage.setItem('theme', 'dark'); // 存储
const theme = localStorage.getItem('theme'); // 读取
localStorage.removeItem('theme'); // 删除
localStorage.clear(); // 清空
// 存储对象
const user = { id: 1, name: 'John' };
localStorage.setItem('user', JSON.stringify(user));
const storedUser = JSON.parse(localStorage.getItem('user'));
最佳实践:
- 存储用户偏好设置(主题/语言等)
- 配合
storage事件实现跨标签页通信 - 敏感数据需加密存储
- 避免存储 >1MB 数据
3. sessionStorage
核心特性:
- 会话级存储:关闭标签页自动清除数据
- 标签页隔离:不同标签页不共享数据
- 刷新保留:页面刷新不丢失数据
- 同步API:操作方式同localStorage
- 容量:5-10MB
// 表单数据临时存储
document.getElementById('form').addEventListener('input', (e) => {
sessionStorage.setItem(e.target.name, e.target.value);
});
// 页面恢复时填充
window.addEventListener('load', () => {
const inputs = document.querySelectorAll('input');
inputs.forEach(input => {
const savedValue = sessionStorage.getItem(input.name);
if(savedValue) input.value = savedValue;
});
});
典型场景:
- 多步骤表单草稿保存
- 单页应用(SPA)路由状态保持
- 敏感操作临时令牌存储
4. IndexedDB
核心架构:
核心特性:
- 非关系型数据库:支持键值对、文档和二进制数据
- 异步API:所有操作非阻塞
- 事务支持:原子性操作保障数据一致性
- 索引查询:支持高性能复杂查询
- 大容量:可达磁盘空间的50%(通常 >250MB)
// 打开/创建数据库
const request = indexedDB.open('myDB', 2);
request.onupgradeneeded = (event) => {
const db = event.target.result;
if (!db.objectStoreNames.contains('users')) {
const store = db.createObjectStore('users', { keyPath: 'id' });
store.createIndex('name_idx', 'name', { unique: false });
}
};
// 添加数据
async function addUser(user) {
const db = await request;
const tx = db.transaction('users', 'readwrite');
await tx.store.add(user);
await tx.done;
}
// 查询数据
async function getUser(id) {
const db = await request;
const tx = db.transaction('users', 'readonly');
return tx.store.get(id);
}
高级功能:
- 游标遍历大数据集
- 二进制文件存储(Blob/ArrayBuffer)
- 复合索引多条件查询
- 版本迁移管理
5. WebSQL(已废弃)
核心特性:
- 关系型数据库:基于SQLite实现
- SQL语法:支持SELECT/INSERT/UPDATE等操作
- 异步API:通过事务执行SQL
- 容量:5-50MB(浏览器限制)
// 创建数据库(已废弃,仅作参考)
const db = openDatabase('mydb', '1.0', 'My DB', 2 * 1024 * 1024);
// 执行SQL
db.transaction(tx => {
tx.executeSql('CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)');
tx.executeSql('INSERT INTO users (name) VALUES (?)', ['Alice']);
tx.executeSql('SELECT * FROM users', [], (_, results) => {
for (let i = 0; i < results.rows.length; i++) {
console.log(results.rows.item(i));
}
});
});
致命缺陷:
- ⚠️ 已被W3C正式废弃(2010年)
- ⚠️ 仅WebKit内核浏览器支持(Chrome/Safari)
- ⚠️ 安全漏洞风险高
- ⚠️ 无跨浏览器兼容性
三、场景化选型指南
1. 🍪 必须选择 Cookie 的场景
-
用户身份认证:存储会话ID(配合
HttpOnly+Secure)Set-Cookie: session_id=abc123; HttpOnly; Secure; SameSite=Lax -
跨子域共享数据:设置顶级域名作用域
document.cookie = "pref_lang=en; domain=.example.com; path=/"; -
符合GDPR的跟踪(需用户同意后设置)
2. 💾 选择 localStorage 的场景
-
用户偏好设置持久化
// 保存主题偏好 localStorage.setItem('theme', 'dark'); // 读取设置 const theme = localStorage.getItem('theme') || 'light'; -
静态资源缓存(配合版本控制)
const cacheVersion = 'v2'; if (localStorage.getItem('cacheVer') !== cacheVersion) { localStorage.clear(); localStorage.setItem('cacheVer', cacheVersion); }
3. 🚀 选择 sessionStorage 的场景
-
单页应用(SPA)路由状态保持
// 保存当前页面状态 window.addEventListener('beforeunload', () => { sessionStorage.setItem('formData', JSON.stringify(formState)); }); -
敏感操作临时令牌存储
// 存储两步验证令牌(会话级安全) sessionStorage.setItem('mfa_token', temporaryToken); -
防止表单重复提交
if (!sessionStorage.getItem('formSubmitted')) { submitForm(); sessionStorage.setItem('formSubmitted', 'true'); }
4. 🗃️ 必须选择 IndexedDB 的场景
-
离线优先应用数据存储
// 保存文章草稿 const db = await openDB('NotesDB', 1, { upgrade(db) { db.createObjectStore('drafts', { keyPath: 'id' }); } }); await db.put('drafts', { id: Date.now(), title: '未命名文档', content: '...', updated: new Date() }); -
大型数据集缓存(>10MB)
// 存储产品目录 const products = await fetch('/api/products'); const tx = db.transaction('products', 'readwrite'); const store = tx.objectStore('products'); products.forEach(p => store.put(p)); -
文件/二进制数据处理
// 存储用户上传的文件 const file = input.files[0]; const buffer = await file.arrayBuffer(); await db.put('userFiles', { id: file.name, data: buffer, type: file.type, size: file.size });
5. ⚠️ 避免使用 WebSQL 的场景
所有新项目都应避免使用 WebSQL,因为:
- 已被 W3C 正式弃用
- 仅支持 WebKit 内核浏览器
- 无事务隔离级别保证
- 被 IndexedDB 全面超越
终极选型原则
- 会话管理 → Cookie(
HttpOnly+Secure) - 小量持久数据 → localStorage
- 临时会话数据 → sessionStorage
- 大型/结构化数据 → IndexedDB
- 文件/二进制数据 → IndexedDB + OPFS
- 关系型数据 → 服务端数据库 + IndexedDB缓存
- 任何新项目 → 禁止使用WebSQL
决策口诀:
认证会话用Cookie,
用户设置localStorage;
草稿状态session,
大型数据IndexedDB;
WebSQL已作古,
未来拥抱OPFS!
四、混合存储策略示例
电商网站最佳实践
代码实现
// 混合存储管理器
class StorageManager {
constructor() {
this.authToken = null;
}
// 初始化存储
async init() {
this.authToken = this.getCookie('session_token');
// 初始化IndexedDB
this.db = await openDB('EcommerceDB', 2, {
upgrade(db) {
if (!db.objectStoreNames.contains('cart')) {
db.createObjectStore('cart', { keyPath: 'sku' });
}
if (!db.objectStoreNames.contains('catalog')) {
const store = db.createObjectStore('catalog', { keyPath: 'id' });
store.createIndex('category_idx', 'category');
}
}
});
}
// Cookie操作
getCookie(name) {
/* ... */
}
// 保存购物车
async saveCart(items) {
const tx = this.db.transaction('cart', 'readwrite');
await Promise.all([
...items.map(item => tx.store.put(item)),
tx.done
]);
// 同步备份到sessionStorage
sessionStorage.setItem('cart_last_updated', Date.now());
}
// 保存用户设置
savePreferences(prefs) {
localStorage.setItem('user_prefs', JSON.stringify(prefs));
}
}