前端存储cookie、sessionStorage、localStorage、websql与indexeddb

1. cookie

1.1 什么是cookie

HTTP协议本身是无状态的。什么是无状态呢,即服务器无法判断用户身份。Cookie实际上是一小段的文本信息(key-value格式)。客户端向服务器发起请求,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态,常用于存放token信息。

打个比方,我们去银行办理储蓄业务,第一次给你办了张银行卡,里面存放了身份证、密码、手机等个人信息。当你下次再来这个银行时,银行机器能识别你的卡,从而能够直接办理业务。

服务器端向客户端发送Cookie是通过HTTP响应报文实现的,在Set-Cookie中设置需要像客户端发送的cookie,cookie格式如下:

Set-Cookie: "name=value;domain=.domain.com;path=/;expires=Sat, 11 Jun 2016 11:29:42 GMT;HttpOnly;secure"

其中name=value是必选项,其它都是可选项。Cookie的主要构成如下:

name:一个唯一确定的cookie名称。通常来讲cookie的名称是不区分大小写的;

value:存储在cookie中的字符串值。最好为cookie的name和value进行url编码;

domain:cookie对于哪个域是有效的。所有向该域发送的请求中都会包含这个cookie信息。这个值可以包含子域(如:yq.aliyun.com),也可以不包含它(如:.aliyun.com,则对于aliyun.com的所有子域都有效);

path: 表示这个cookie影响到的路径,浏览器跟会根据这项配置,像指定域中匹配的路径发送cookie;

expires:失效时间,表示cookie何时应该被删除的时间戳(也就是,何时应该停止向服务器发送这个cookie)。如果不设置这个时间戳,浏览器会在页面关闭时即将删除所有cookie;不过也可以自己设置删除时间。这个值是GMT时间格式,如果客户端和服务器端时间不一致,使用expires就会存在偏差;

max-age: 与expires作用相同,用来告诉浏览器此cookie多久过期(单位是秒),而不是一个固定的时间点。正常情况下,max-age的优先级高于expires;

HttpOnly: 告知浏览器不允许通过脚本document.cookie去更改这个值,同样这个值在document.cookie中也不可见。但在http请求张仍然会携带这个cookie。注意这个值虽然在脚本中不可获取,但仍然在浏览器安装目录中以文件形式存在。这项设置通常在服务器端设置;

secure: 安全标志,指定后,只有在使用SSL链接时候才能发送到服务器,如果是http链接则不会传递该信息。就算设置了secure 属性也并不代表他人不能看到你机器本地保存的 cookie 信息,所以不要把重要信息放cookie就对了服务器端设置。

1.2 cookie运行机制

当用户第一次访问并登陆一个网站的时候,cookie的设置以及发送会经历以下4个步骤:

  • 客户端发送一个请求到服务器;
  • 服务器发送一个HttpResponse响应到客户端,其中包含Set-Cookie的头部;
  • 客户端保存cookie,之后向服务器发送请求时,HttpRequest请求中会包含一个Cookie的头部 ;
  • 服务器返回响应数据。

浏览器输入地址进行访问,结果如图所示:

可见Response Headers中包含Set-Cookie头部,而Request Headers中包含了Cookie头部。

1.3 cookie属性项

1.3.1 Expires

该属性用来设置Cookie的有效期。Cookie中的maxAge用来表示该属性,单位为秒。Cookie中通过getMaxAge()和setMaxAge(int maxAge)来读写该属性。maxAge有3种值,分别为正数,负数和0。

  • 如果maxAge属性为正数,则表示该Cookie会在maxAge秒之后自动失效。浏览器会将maxAge为正数的Cookie持久化,即写到对应的Cookie文件中(每个浏览器存储的位置不一致)。无论客户关闭了浏览器还是电脑,只要还在maxAge秒之前,登录网站时该Cookie仍然有效。下面代码中的Cookie信息将永远有效。
  • 当maxAge属性为负数,则表示该Cookie只是一个临时Cookie,不会被持久化,仅在本浏览器窗口或者本窗口打开的子窗口中有效,关闭浏览器后该Cookie立即失效。
  • 当maxAge为0时,表示立即删除Cookie

那么maxAge设置为负值和0到底有什么区别呢?

  • maxAge设置为0表示立即删除该Cookie,如果在debug的模式下,执行上述方法,可以看见cookie立即被删除了。
  • maxAge设置为负数,能看到Expires属性改变了,但Cookie仍然会存在一段时间直到关闭浏览器或者重新打开浏览器。

1.3.2 Cookie的域名

Cookie是不可以跨域名的,隐私安全机制禁止网站非法获取其他网站的Cookie。

正常情况下,同一个一级域名下的两个二级域名也不能交互使用Cookie,比如test1.mcrwayfun.com和test2.mcrwayfun.com,因为二者的域名不完全相同。如果想要mcrwayfun.com名下的二级域名都可以使用该Cookie,需要设置Cookie的domain参数为.mcrwayfun.com,这样使用test1.mcrwayfun.com和test2.mcrwayfun.com就能访问同一个cookie。

一级域名又称为顶级域名,一般由字符串+后缀组成。熟悉的一级域名有baidu.com,qq.com。com,cn,net等均是常见的后缀。
二级域名是在一级域名下衍生的,比如有个一级域名为mcrfun.com,则blog.mcrfun.comwww.mcrfun.com均是其衍生出来的二级域名。

1.3.3 Cookie的路径

path属性决定允许访问Cookie的路径。比如,设置为"/"表示允许所有路径都可以使用Cookie。

1.4 js-cookie插件

$ npm install js-cookie --save

Cookies.set('name', 'value');
Cookies.set('name', 'value', { expires: 7 });
Cookies.set('name', 'value', { expires: 7, path: '' });

Cookies.get('name'); // => 'value'
Cookies.get('nothing'); // => undefined
Cookies.get(); // => { name: 'value' }
Cookies.remove('name');

Cookies.set('name', 'value', { path: '' });
Cookies.remove('name'); // fail!
Cookies.remove('name', { path: '' }); // removed!

// 封装
import Cookies from 'js-cookie'

const TokenKey = 'Admin-Token'

export function getToken() {
  return Cookies.get(TokenKey)
}

export function setToken(token) {
  return Cookies.set(TokenKey, token)
}

export function removeToken() {
  return Cookies.remove(TokenKey)
}

2. 短暂的sessionStorage

2.1 是什么

sessionStorage属于webstorage的一种,sessionStorage与我们稍后要说的localStorage类似,可以存储k-v形式的数据,使用方法非常简单set便可以存储。

sessionStorage.setItem('test', 'doctorhou');
sessionStorage.getItem('test');
sessionStorage.removeItem('test');

2.2 访问限制性

  • 不同于cookie,sessionStorage的访问限制更高一些,只有当前设定sessionStorage的域下才能访问,而且不同的两个tab之间不能互通。例,我在www.qq.com下种下了sessionStorage,在wx.qq.com下是,无法访问的;
  • 在新开的tab下,或者关闭本TAB再打开后(也是www.qq.com),也是无法访问到之前种的sessionStorage的;
  • 而本tab刷新的时候,sessionStorage确是可以访问的。

以上种种,证明sessionStorage里面的session,并不同于cookie,是以tab为级别的session。

2.3 做什么用比较好?

既然是存储于客户端而且存储级别仅仅是一个session的话,还是建议存储一些当前页面刷新需要存储,且不需要在tab关闭时候留下的信息。刚刚说了,只有页面刷新才不会清除掉sessionStorage。剩下的均会清理掉sessionStorage,当然,也许可以用sessionStorage来检测用户是否是刷新进入的页面。对于音乐播放器恢复播放进度条等功能等还是挺实用的。

3 简易强大的localStorage

3.1 是什么?

localStorage与sessionStorage较为相似,接口也简单,通过localStorage.setItem/localStorage.getItem即可轻松使用。localStorage的存储周期比sessionStorage长,如果用户不清理的话,是可以永久存储的。

localStorage.setItem('test', 'doctorhou');
localStorage.getItem('test');

var doctorhou = {
    name: 'doctorhou',
    describe: '高大、威猛、帅气'
};
localStorage.setItem('test', JSON.stringify(doctorhou));
JSON.parse(localStorage.getItem('test'));

3.2 访问的限制性

localStorage与sessionStorage虽然相似,但是访问限制却不尽相同,localStorage的访问域默认设定为设置localStorage的当前域,其他域名不可以取。这点与sessionStorage相同,但是与sessionStorage不同的是,localStorage设定后,新开tab是可以访问到的。

3.3 存储时间

localStorage理论上讲是永久性质的存储。但是,免不了用户会使用浏览器清除数据,或者浏览器有时候为了节省,去清除数据。

3.4 大小限制及检测

localStorage的大小一般限定为4M左右,这点可以根据实际浏览器来测试。那么,如何检测自己已经消耗了多少空间呢?可以直接将localStorage序列化,看看其字节数,就可以算出其已经占用的空间了(可能会有点误差,这样做会把一些转移符号算进去,可以消除掉后再算)。

clipboard.png

3.5 做什么用比较好

由于localStorage的稳定性质,及其长效的存储。笔者建议如果有一些数据,服务器难以承载其压力,但又要与用户的信息绑定的话,可以使用localStorage存储一些状态,这样即能缓解服务端压力,也可以存储用户的数据。当然,也有一些小技巧,可以用localStorage提高网站访问的速度。如笔者写的一篇浅析文章:
聊一聊百度移动端首页前端速度那些事儿

4 websql与indexeddb

4.1 是什么?

这两位可是web存储中的重型武器。为什么放在一起说呢,是因为,websql的标准,官方已经不打算维护了,转而维护了新的indexeddb,读者可能会问了,那直接说indexeddb就好了,为啥还要说websql,因为websql虽然过时了,但是其兼容性却出奇的好,几乎是移动端均可用呀。我们来看一下caniuse上的兼容性数据:

websql的兼容性如图

clipboard.png

indexeddb的兼容性却不是很好,android4.4之前以及ios7以前都无法使用。

clipboard.png

所以笔者建议如下,能用indexeddb的时候,就要使用indexeddb,因为其代表了未来的发展方向。如果用不了indexeddb的尽量使用websql进行代替。其实就是使用一段腻子脚本(polyfill)即可,做一下兼容。接下来我们会尝试做一点腻子脚本。

websql更像是关系型数据库,并且使用sql语句进行操作

<!doctype html>
<html>
    <head>
        <meta charset="utf-8" />
    </head>
    <body>
        <script>
            var db = window.openDatabase('testDB', '1.0', 'TestDb', 2 * 1024 * 1024);
            db.transaction(function (context) {
                context.executeSql('CREATE TABLE IF NOT EXISTS cubefe(id, name)');
                context.executeSql('INSERT INTO cubefe (id, name) VALUES (1, "doctorhou")');
            }); 
        </script>
    </body>
</html>

clipboard.png

indexeddb更像是nosql,直接使用js的方法操作数据即可,

<!doctype html>
<html>
    <head>
        <meta charset="utf-8" />
    </head>
    <body>
        <script>
            var startTime = +new Date();
            console.log('starttime:', startTime);
            function openDB(dbname, version, cb) {
                var request = window.indexedDB.open(dbname);
                request.onsuccess = function (e) {
                    var db = e.target.result;
                    myDB.db = db;
                    var version = db.version;
                    if (!db.objectStoreNames.contains('students')) {
                        request = db.createObjectStore('students', {autoIncrement: true});
                    }
                    cb && cb(e);
                };
            }   

            var myDB = {
                name: 'test',
                version: 4,
                db: null
            };

            openDB(myDB.name, myDB.version, function (e) {
                var db = e.target.result;
                var storeName = 'students';
                var transaction = db.transaction(storeName, 'readwrite');
                var store = transaction.objectStore(storeName);
                store.put({id: 2, name: 'doctorhou'}, 'b');
                var request = store.get(1);
                request.onsuccess = function (e) {
                    console.log(request.result);
                    var endTime = +new Date();
                    console.log('take-time:', endTime - startTime);
                };
            });

        </script>
    </body>
</html>

clipboard.png

4.2 访问

indexeddb和websql在这一点上与localStorage一致,均是在创建数据库的域名下才能访问。而且不能指定访问域名。

4.3 存储时间

这两位的存储时间也是永久,除非用户清除数据,可以用作长效的存储。

4.4 大小限制

理论上讲,这两种存储的方式是没有大小限制的。然而indexeddb的数据库超过50M的时候浏览器会弹出确认。基本上也相当于没有限制了。

4.5 性能如何?

我这边做了个实验,indexeddb查询少量数据也就花费了20MS左右。还是很快的。

大量数据的情况下,相对耗时会变长一些,但是也就在30MS左右,也是相当给力了。如图4.5.2所示,10W数据+,毕竟nosql。

而websql这边的效率也不错,10w+数据,简单查询一下,只花费了20MS左右。

4.6 拿来干什么用?

当我们是在做一个离线应用,或者webapp的时候,可以考虑使用本地数据库中存取数据。如果不存大量的数据的话,其实localStorage就够用了。亦或者,你想把一张用户的皮肤图片之类的大量数据存入客户端缓存起来,localStorage已经不够用了的话,也可以尝试一下websql与indexeddb。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值