Appearance
Cookie 与 Web Storage
一、Cookie 核心机制解析
1.1 诞生背景与核心特性
- 无状态协议补偿:为解决 HTTP 无状态特性设计,实现会话跟踪
- 客户端存储:浏览器自动管理存储/传输,最大容量 4KB
- 同源策略:
- 域名绑定:
www.baidu.com
与aa.baidu.com
默认隔离 - 端口隔离:
80
端口与8080
端口 Cookie 不共享
- 域名绑定:
1.2 属性详解表
属性 | 说明 | 最佳实践 |
---|---|---|
Domain | 定义有效域名(默认当前域名) | .baidu.com 实现多级子域共享 |
Path | 定义有效路径(默认 / ) | /api 限制 API 接口专用 Cookie |
Expires | 绝对过期时间(GMT 格式) | 长期登录凭证存储 |
Max-Age | 相对有效期(秒),优先级高于 Expires | 临时会话管理(如验证码) |
Secure | 仅 HTTPS 传输 | 敏感信息必须设置 |
HttpOnly | 禁止 JavaScript 访问 | 防御 XSS 攻击 |
SameSite | 控制跨站请求携带(Strict/Lax/None) | 防御 CSRF 攻击(需配合 Secure) |
1.3 高级应用场景
javascript
// 设置安全 Cookie 示例
document.cookie =
"session_id=abc123; Domain=.baidu.com; Path=/; Secure; HttpOnly; SameSite=Strict; Max-Age=3600";
// 读取 Cookie(需自行解析)
function getCookie(name) {
return document.cookie.split("; ").reduce((res, c) => {
const [key, val] = c.split("=").map(decodeURIComponent);
return key === name ? val : res;
}, "");
}
二、Web Storage 进阶指南
2.1 存储特性对比
特性 | localStorage | sessionStorage | Cookie |
---|---|---|---|
存储容量 | 5MB | 5MB | 4KB |
生命周期 | 持久化 | 标签页关闭 | 可配置 |
作用域 | 同源不限窗口 | 同源+同窗口 | 同源+域名/路径限制 |
API 类型 | 同步 | 同步 | 同步/异步(Document-cookie) |
事件通知 | storage 事件 | 无 | 无 |
2.2 实用代码模板
javascript
// localStorage 持久化存储
const USER_SETTINGS_KEY = "user_prefs";
// 保存设置
function saveSettings(settings) {
localStorage.setItem(
USER_SETTINGS_KEY,
JSON.stringify({
...settings,
timestamp: Date.now(),
})
);
}
// 读取设置
function loadSettings() {
const raw = localStorage.getItem(USER_SETTINGS_KEY);
return raw ? JSON.parse(raw) : {};
}
// sessionStorage 临时存储
function saveTempData(key, data) {
sessionStorage.setItem(key, JSON.stringify(data));
}
// 跨窗口通信(通过 storage 事件)
window.addEventListener("storage", (e) => {
if (e.key === "shared_data") {
console.log("收到其他窗口更新:", JSON.parse(e.newValue));
}
});
js
// 打开一个新tab标签,加上opener可以复制sessionStorage,修改不会共享
<a href="./other.html" target="_blank" rel="opener">
打开新页面
</a>
三、安全防护最佳实践
3.1 Cookie 安全强化方案
- 敏感数据保护:
- 避免存储明文密码等敏感信息
- 使用 HttpOnly 阻止 XSS 窃取
- 传输安全:
- 强制 Secure 属性(HTTPS 环境)
- 设置 SameSite=Strict 防御 CSRF
- 生命周期管理:
- 短期数据使用 Max-Age
- 长期数据配合刷新令牌机制
3.2 Web Storage 安全风险
XSS 攻击:恶意脚本可读写全部数据
防御方案:
javascript// 输入过滤 function sanitizeInput(input) { const div = document.createElement("div"); div.textContent = input; return div.innerHTML; } // 存储加密 function saveSecureData(key, data) { const encrypted = CryptoJS.AES.encrypt( JSON.stringify(data), SECRET_KEY ).toString(); localStorage.setItem(key, encrypted); }
四、性能优化策略
4.1 Cookie 优化技巧
减少体积:避免存储大型数据(超过 4KB 会被截断)
作用域精准化:
javascript// 错误示范:设置全局 Path document.cookie = "temp_data=xxx; Path=/"; // 正确做法:限制作用域 document.cookie = "temp_data=xxx; Path=/api";
过期策略:及时清理过期 Cookie(可通过 Max-Age 自动管理)
4.2 Web Storage 优化方案
- 定期清理:实现存储空间监控
javascript
// 计算空间占用
const getAccurateStorageUsage = () => {
let totalBytes = 0;
const encoder = new TextEncoder();
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
const value = localStorage.getItem(key) || "";
totalBytes += encoder.encode(key).byteLength;
totalBytes += encoder.encode(value).byteLength;
}
return totalBytes;
};
// 智能清理策略
const cleanupStorage = (prefix, keepCount = 10) => {
const allKeys = [];
const encoder = new TextEncoder();
// 收集符合前缀的键并解析元数据
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
if (key.startsWith(prefix)) {
allKeys.push({
key,
size:
encoder.encode(key).byteLength +
encoder.encode(localStorage.getItem(key) || "").byteLength,
});
}
}
allKeys.slice(0, -keepCount).forEach((item) => {
console.log(`[清理] ${item.key} (${item.size}B)`);
localStorage.removeItem(item.key);
});
};
// 空间监控与自动清理
const checkStorageSpace = (
options = {
maxWarning: 4.5 * 1024 * 1024, // 4.5MB 预警阈值
cleanupPrefix: "app:", // 默认清理前缀
keepCount: 10, // 默认保留条目数
}
) => {
const used = getAccurateStorageUsage();
const mbUsed = (used / 1024 / 1024).toFixed(2);
console.log(`💾 当前存储占用: ${mbUsed}MB`);
if (used > options.maxWarning) {
console.warn(`⚠️ 存储空间超过 ${mbUsed}MB,触发自动清理`);
cleanupStorage(options.cleanupPrefix, options.keepCount);
}
};
const setStorage = (key, data={}) => {
data = JSON.stringify(data) || "";
const encoder = new TextEncoder();
const size = encoder.encode(key).byteLength +
encoder.encode(data).byteLength,
localStorage.setItem(key, data);
console.log(`✅ 添加数据: ${key} (${size}B)`);
};
const getStorage = (key) => {
return JSON.parse(localStorage.getItem(key) || "{}");
};
window.addEventListener("storage", (e) => {
if (e.storageArea === localStorage) {
console.log(`🔔 检测到存储变化: ${e.key} = ${e.newValue}`);
checkStorageSpace(); // 可选:自动重新检查
}
});
export {
getAccurateStorageUsage,
cleanupStorage,
checkStorageSpace,
setStorage,
};
五、选型决策树
mermaid
graph TD
A[需要存储数据] --> B{数据类型}
B -->|敏感信息| C[Cookie + Secure/HttpOnly]
B -->|非敏感信息| D{生命周期}
D -->|持久化| E[localStorage]
D -->|临时| F{作用域需求}
F -->|跨窗口| E
F -->|单窗口| G[sessionStorage]
C --> H{数据量}
H -->|≤4KB| C
H -->|>4KB| I[需改用 Web Storage]
六、常见问题解决方案
6.1 Cookie 跨域共享
javascript
// 主域设置
document.cookie = "shared_cookie=123; Domain=.example.com; Path=/";
// 子域读取(如 a.example.com)
console.log(document.cookie.includes("shared_cookie")); // true