前端浏览器数据存储
在前端开发中,浏览器存储是保存数据的重要方式之一。常见的浏览器存储方案有cookie、localStorage、sessionStorage、indexDB等。选择合适的存储方案对应用性能和用户体验有重要影响。
1. cookie
cookie内容请参考Cookie专题
2. sessionStorage
sessionStorage为每一个给定的源(given origin)维持一个独立的存储区域,该存储区域在页面会话期间可用(即只要浏览器处于打开状态,包括页面重新加载和恢复)。
js
// 保存数据到 sessionStorage
sessionStorage.setItem('key', 'value');
// 从 sessionStorage 获取数据
var data = sessionStorage.getItem('key');
// 从 sessionStorage 删除保存的数据
sessionStorage.removeItem('key');
// 从 sessionStorage 删除所有保存的数据
sessionStorage.clear();
sessionStorage在创建时便已确定了生命周期,即在当前标签页关闭时数据会被清除。
2.1 应用场景
- 临时表单数据保存(防止页面刷新丢失)
- 页面间临时数据传递
- 多步骤表单的状态管理
- 临时购物车信息
3. localStorage
localStorage 同样为每一个给定的源(given origin)维持一个独立的存储区域,但其生命周期不会因为标签页的关闭而清除,除非主动清除。
js
// 保存数据到 localStorage
localStorage.setItem('key', 'value');
// 从 localStorage 获取数据
var data = localStorage.getItem('key');
// 从 localStorage 删除保存的数据
localStorage.removeItem('key');
// 从 localStorage 删除所有保存的数据
localStorage.clear();
3.1 数据存储优化
js
// 对于复杂对象,使用JSON序列化
const userInfo = {
name: '张三',
age: 25,
preferences: ['reading', 'coding']
};
// 存储
localStorage.setItem('userInfo', JSON.stringify(userInfo));
// 读取
const storedUserInfo = JSON.parse(localStorage.getItem('userInfo') || '{}');
3.2 存储空间检测
js
// 检查localStorage是否可用
function isLocalStorageAvailable() {
try {
const test = '__test__';
localStorage.setItem(test, test);
localStorage.removeItem(test);
return true;
} catch(e) {
return false;
}
}
// 检查存储空间
function getLocalStorageSize() {
let size = 0;
for(let key in localStorage) {
if(localStorage.hasOwnProperty(key)) {
size += localStorage[key].length;
}
}
return size;
}
3.3 数据过期处理
js
// 带过期时间的localStorage封装
class StorageWithExpiration {
static set(key, value, ttl) {
const data = {
value: value,
expiry: new Date().getTime() + ttl,
};
localStorage.setItem(key, JSON.stringify(data));
}
static get(key) {
const item = localStorage.getItem(key);
if (!item) {
return null;
}
const data = JSON.parse(item);
if (new Date().getTime() > data.expiry) {
localStorage.removeItem(key);
return null;
}
return data.value;
}
}
// 使用示例
StorageWithExpiration.set('tempData', 'temporary value', 5000); // 5秒过期
const value = StorageWithExpiration.get('tempData');
3.4 应用场景
- 用户偏好设置(主题、语言等)
- 长期缓存的数据(如城市列表、用户信息)
- 离线应用的数据存储
- 购物车持久化
4. 浏览器存储方案对比
特性 | cookie | localStorage | sessionStorage | indexDB |
---|---|---|---|---|
生命周期 | 一般由服务器生成,可以设置过期时间 | 除非被清理,否则一直存在 | 页面会话期间可用(标签页关闭即清除) | 除非被清理,否则一直存在 |
存储大小 | 4KB | 5MB | 5MB | 无限 |
与服务端通信 | 每次都会携带在header中,对于请求性能有影响 | 仅在客户端存储,不与服务端通信 | 仅在客户端存储,不与服务端通信 | 仅在客户端存储,不与服务端通信 |
存储方式 | 只能存储字符串类型数据 | 只能存储字符串类型数据 | 只能存储字符串类型数据 | 可以存储任何类型数据 |
同步/异步 | 同步 | 同步 | 同步 | 异步 |
5. sessionStorage数据共享机制
html
<!-- 使用一个新标签页打开自身,并设置一个 sessionStorage -->
<a href="index.html" target="_blank" onclick="sessionStorage.setItem('name', 'liam')">open myself</a>
- 在浏览器中打开这个 index.html,我们称之为标签页 A。注意:需要用 http 协议打开!例如 http://localhost/index.html
- 点击页面上的链接,此时会弹出来标签页 B。
- 在标签页 B 中打开控制台并执行 sessionStorage.getItem('j')
- 控制台输出's',这说明标签页 A 和 B 共享了 sessionStorage 中的数据
- 接下来,先关闭这两个标签页,然后再打开一个标签页 C,再读取一下 j 的值,得到的是 null
但是如果进行如下操作发现表现与预期不符合:
- 在浏览器中打开这个 index.html,我们称之为标签页 A。注意:需要用 http 协议打开!例如 http://localhost/index.html
- 点击页面上的链接,此时会弹出来标签页 B。
- 在标签页 B 中打开控制台并执行 sessionStorage.getItem('j'),得到 's'
- 新建一个新标签页 D,然后在地址栏内输入 http://localhost/index.html 打开同样的页面, 然后执行 sessionStorage.getItem('j')
- 按照我的预期,标签页 D 得到的应该还是 's',毕竟我认为 sessionStorage 的数据是在同一网站的多个标签页之间共享的。但是我错了,得到的结果是 null
标签页 B 和标签页 D 之间唯一的不同就是它们被打开的方式:标签页 B 是通过在标签页 A 中点击链接打开的,但标签页 D 是在浏览器地址栏输入地址打开的
通过点击链接(或者用了 window.open)打开的新标签页之间是属于同一个 session 的(因为她们共用了同一个浏览器的进程),但新开一个标签页总是会初始化一个新的 session,即使网站是一样的,它们也不属于同一个 session
localStorage - 只要是同源,不同 Tab 之间均可读写,相互影响。 sessionStorage - 前提还是同源, 同一 Tab 在新标签或窗口打开一个页面时会复制顶级浏览会话的上下文作为新会话的上下文,复制之后读写操作独立,"互不影响"。 不同 Tab 之间,读写操作独立,"互不影响"。 上面打引号原因是,<a target="_blank"></a>
和 window.open() 两种方式创建新 Tab 的初始缓存不一样。前者是全新的一个 sessionStorage 对象,且初始值为空。后者则基于原页面的 sessionStorage 拷贝一份,并作为新 Tab 的初始缓存值。 Cookie - 只要 Domain 和 Path 一致情况下,不同 Tab 之间即可相互读取。Cookie 最宽松的情况是同站即可,就是说 Domain 设为二级域名、Path 设为 /。
sessionStorage 的数据会在同一网站的多个标签页之间共享吗?这取决于标签页如何打开
6. 安全注意事项
- 敏感信息不应存储在客户端存储中
- 对于用户身份凭证,应使用HttpOnly cookie
- 注意存储数据的隐私合规性
- 定期清理不需要的存储数据