谈谈HTML5本地存储

Posted on 2017-08-15 |    

这次在写项目的登录认证过程中,碰到了一点小问题,是关于浏览器存储方面的东西,就仔细查了资料,总结一下。

浏览器本地存储概述

简介

cookie

cookie是指某些网站为了辨别用户身份、进行 session 跟踪而储存在用户本地终端上的数据(通常经过加密)。

webStorage

webStorage是HTML5中本地存储的解决方案之一,包括sessionStorag和localStorage,两者差別就差在生命周期的不同而已。

websql和indexeddb

IndexedDB 是一种低级API,用于客户端存储大量结构化数据。该API使用索引来实现对该数据的高性能搜索。webStorage 对于存储较少量的数据很有用,但对于存储更大量的结构化数据来说,这种方法不太有用。IndexedDB提供了一个解决方案。

websql是早期的存储标准,目前已经不再维护,转向indexeddb,不过websql的兼容性更好。不过indexeddb是未来,所以接下来主要讲indexeddb

四者对比

类型 生命周期 存储大小 与服务器通信 作用域 使用场景
Cookie 一般由服务器生成,可设置过期时间,默认是关闭浏览器后失效 4k左右 可每次携带在http头部中,但保存过多数据会带来性能问题 可通过.setDomain设置主域名共享 不建议在cookie里存储数据,必要时存储同步访问页面时必须要被带到服务端的信息,例如网站的用户登录信息
localStorage 永久保存,除非被清除 5m左右 只能存储在浏览器端 子域名之间相互独立 存储用户的一些状态和数据,缓解服务器压力
sessionStorage 仅存在当前标签页下,关闭浏览器或者新建标签页都为空 5m左右 只能存储在浏览器端 不同tab之间无法共享 建议存储一些当前页面刷新需要存储,且不需要在tab关闭时候留下的信息,可根据这个来判断用户是否刷新进入,恢复音乐视频播放进度等
indexeddb 永久保存,除非被清除 一个单独的数据库没有大小限制,不过可能限制每个Indexeddb数据库的大小,例如firefox在用户界面上只会针对存储超过 50 MB 大小的 BLOB(二进制大对象)请求权限,总体基本没有大小限制 只能存储在浏览器端 子域名之间相互独立 离线应用或webapp可以考虑使用indexeddb或者websql中存取数据

【tip】sessionStorage只能在一个标签页下共享,即如果你从当前标签页下新打开一个该网页的页面,sessionStorage数据也是清空的。不过如果你恢复关闭的页面的话,在chrome和firefox下sessionStorage也会被恢复,不过safari不会。

webStorage和indexeddb的兼容性

webStorage兼容性

Chrome Firefox IE Opera Safari
localStorage 4 3.5 8 10.50 4
sessionStorage 5 2 8 10.50 4

基本浏览器都是支持的

indexeddb兼容性

Chrome Firefox IE Opera Safari
l异步 API 12 【webkit 】 16.0 (16.0) 4.0 (2.0)【 moz】 10 【ms】 未实现 未实现
同步 API 未实现 未实现 未实现 未实现 未实现

目前兼容性较差

webStorage API

localStorage和sessionStorage的用法是一样的,下面展示sessionStorage的使用例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 保存数据到sessionStorage
sessionStorage.setItem('key', 'value');

// 从sessionStorage获取数据
var data = sessionStorage.getItem('key');

// 从sessionStorage删除保存的数据
sessionStorage.removeItem('key');

// 从sessionStorage删除所有保存的数据
sessionStorage.clear();

//枚举sessionStorage的方法

for(var i=0;i<sessionStorage.length;i++){
var key = sessionStorage.key(i);
var value =sessionStorage.getItem(key);
}

当然,你也可以直接用对象的赋值方式来设置

1
2
sessionStorage['colorSetting'] = '#a4509b';
sessionStorage.setItem('colorSetting', '#a4509b');

不过,官方建议只用webStorage API(getItem, removeItem, key, length),来避免使用对象键值存储的一些缺陷,缺陷详情请点击这里

storage事件

webStorage还有storage事件。当storage发生改变,storage事件就会被触发。
这里的的条件是数据发生了变化,如果当前的存储区域是空的,即使再调用clear()也不会触发事件。或者你通过setItem()来设置一个与现有值相同的值,事件也是不会触发的。

storage 属性

属性名 描述
key 代表属性名发生变化.当被clear()方法清除之后所有属性名变为null. Read only(只读).
newValue 新添加进的值.当被clear()方法执行过或者被属性名被删除,值会成为null Read only(只读).
oldValue 原始值.被clear()方法执行过则变为null,或者被新值取代。 Read only(只读).
storageArea 被操作的storage对象. Read only(只读).
url key发生改变的对象所对应的文档的URL地址.。 Read only(只读).

下面介绍多标签页面使用sessionStorage时会有使用栗子。

多标签页面使用sessionStorage

在最近使用vuejs写完全前后端分离的项目时,在做登录认证的时候,在想到底怎么存储用户认证信息。

因为系统安全要求等级比较高,要求用户关闭标签页的时候会话立刻到期,使用cookie来保存敏感的token就不太合适了。如果使用localstorage,页面关闭后localstorage数据还在,也不太满足要求。
想着只能使用sessionStorage。

不过尴尬的是,使用sessionStorage是无法再多标签页面共享的。每次打开新标签页,就会跳转到登录页面,用户体验不太友好,查了一下资料,看到一博客是翻译了一外国小哥使用storage事件实现跨标签页共享sessionStorage的文章,学习了,点击这里看该博客

简单来讲就是,如果新标签页如果没有sessionStorage数据,就会触发一个localstorage修改事件,那么在已存在的标签里收到这个事件后,就会将当前页的sessionStorage数据保存在localstorage中,但是马上移除。但是在新标签页里会监听到该事件,可以获取到这个sessionStorage数据,那这样就保证了新标签页也能获取sessionStorage,也保证localstorage中不存在token信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
(function() {

if (!sessionStorage.length) {
// 如果当前页没有sessionStorage数据,就触发一个事件。
localStorage.setItem('getSessionStorage', Date.now());
};

window.addEventListener('storage', function(event) {

//console.log('storage event', event);

if (event.key == 'getSessionStorage') {
// 已存在的标签页收到该事件后,讲sessionStorage数据存到localstorage中,并马上移除。

localStorage.setItem('sessionStorage', JSON.stringify(sessionStorage));
localStorage.removeItem('sessionStorage');

} else if (event.key == 'sessionStorage' && !sessionStorage.length) {
// 新标签页会在这里监听到事件,通过newValue这个属性获取当时存储在localstorage的sessionStorage数据

var data = JSON.parse(event.newValue),value;
console.log(data,"111");
for (key in data) {
sessionStorage.setItem(key, data[key]);
}

}
});

})();

IndexedDB

用法不像sessionStorage那么简单,不过以下两篇文章把基本indexeddb用法都讲的比较清楚了。就不额外做整理了。

HTML5本地存储——IndexedDB(一:基本使用)
HTML5本地存储——IndexedDB(二:索引)

【参考】
http://blog.kazaff.me/2016/09/09/译-在多个标签页之间共享sessionStorage/?utm_source=tuicool&utm_medium=referral
https://blog.guya.net/2015/06/12/sharing-sessionstorage-between-tabs-for-secure-multi-tab-authentication/
https://developer.mozilla.org/zh-CN/docs/Web/API/Window/sessionStorage
https://segmentfault.com/a/1190000005927232#articleHeader3