web存储详解(cookie、sessionStorage、localStorage、indexedDB)_什么是web存储
5%以上软件测试开发知识点,真正体系化!**
上面我们已经对cookie的来源进行了详细的介绍,这里要介绍的是cookie的用法及特点。
HTTP Cookie简称cookie,是在HTTP请求发送Set-Cookie HTTP头作为响应的一部分,通过name=value的形式存储的字符串。前端收到该响应后,会将cookie保存在浏览器内,并在每次的用户请求中携带该字符串。
cookie在前端可以通过document.cookie获得,如:
document.cookie
< “_ga=77911531582348967; _gid=10966846041582958782”
上面的cookie里共存储了两个参数:_ga和_gid,两个参数由一个分号和一个空格隔开。cookie本身是用encodeURIComponent编码的,因此,如果cookie中包含中文,需要用对应的decodeURIComponent解码才能得到对应值。
除了key和value外,每个参数还会携带其他几个属性,包括域、路径、失效时间、安全标志等,这些参数在使用document.cookie输出时无法看到,不过可以在调试工具中查看:
上面几个参数的含义分别是:
- key,键名。
- value,键值。
- Domain,cookie的域,即该网站所在的域,需要注意的是,cookie的域是不区分端口号的。
- Path,cookie的存储路径,默认是当前项目的根路径。
- Expires/Max-Age,cookie的失效时间,以毫秒为单位。不设置时默认在session失效时失效。
- Size,cookie的大小。
- HttpOnly,是否只能通过http请求传输。某些重要的cookie(如sessionId),只能由后台来设置,并且是不能随意修改的,就可以设置该标志位。
- Secure,安全标志。设置了该参数后,该cookie只在https请求中才会被携带。
- SameSite,为防止CSRF攻击和用户追踪而新增的安全属性,具体可参考阮一峰:Cookie 的 SameSite 属性。
一般来说,cookie只用于保存与登录相关的信息,其中最重要的是服务端会话(session)对象的id。它不适合存储大量的数据,因为浏览器限制了每个cookie的大小不能超过4KB。此外,浏览器对单个域下cookie的数量也是有限制的,该数量因浏览器而异,对开发者来说,这个数量一般不要超过20个。
cookie默认会在会话结束时失效,也可以手动修改max-age
或Expires
参数来设置cookie的失效时间,前者是规定cookie在多少秒后失效,而后者则是规定cookie在某个时间点失效。如果同时设置了这两个参数,则max-age优先级更高。
向cookie添加参数很简单:
document.cookie = “name=oeschger”;
document.cookie = “favorite=tripe;max-age=120;path=/”;
alert(document.cookie);
// 显示: name=oeschger; favorite=tripe
注意,我们为favorite设置的其他参数虽然没有通过document.cookie打印出来,但它们仍然是有效的。比如上面的name会在服务端的session销毁时失效,而favorite则会在120秒后失效。
cookie没有提供直接删除参数的接口,但是可以通过将参数的max-age属性设置为0或者将Expires设置为当前时间,来使其立即失效,以达到删除cookie的目的,如:
document.cookie = “favorite=; max-age=0;”;
这样就可以从cookie中删除favorite。
cookie作为客户端存储,有一个很大的优点,就是不受服务端架构的影响。我们知道,在分布式架构下,session很难在各个服务器之间共享。而cookie则完全不存在这个问题,它存储于客户端,可以被发送到任意一台服务器。
同时,cookie也存在几个很明显的缺点。一个是安全问题,cookie中存储了客户端的身份认证信息,如果被窃取,就可能产生不可预估的损失。另一个是上面提到的容量问题,这使得cookie不能广泛用于web存储。此外,cookie对通信带来的性能损耗也是不可忽视的。因为cookie中的所有参数会在每次向后端发送请求时被携带,如果cookie很大,就会导致每次的http请求体积变大,影响网站的响应速度。综上所述,cookie仅用于保存极少量的用户身份认证信息,并且需要通过加密策略保证cookie传输安全。
2. sessionStorage和localStorage
为什么要把这两个放在一起介绍呢?
因为它们都是继承自Storage
,原理和语法上都有极高的相似性,以至于网上有大量关于两者异同的介绍文章。先来看看它们的相同点:
(1). 相同点
1.从原理上来说,两者都属于浏览器端存储。前者称为“会话存储”,后者称为“本地存储”。它们都被部署在window对象上,因此可以通过下面的方式访问:
window.localStorage
// 或者直接访问localStorage
window.sessionStorage
// 或者直接访问sessionStorage
2.两者的操作语法是一致的(这里以localStorage为例):
localStorage.setItem(“name”, “carter”); // 设置name: carter
localStorage.age = “24”; // 设置age: 24
localStorage.getItem(“name”); // 获取name的值carter
localStorage.removeItem(“name”); // 删除name
localStorage.clear(); // 清空localStorage
sessionStorage的语法同上。
3.两者都遵循同源策略。即该存储只在同一个域下可以共享,跨域无法访问,这样可以保证数据的安全性。
4.localStorage和sessionStorage各自拥有5MB的存储空间,并且只能保存字符串类型的数据。对于非字符串类型的数据,一般需要使用JSON.stringify
方法压缩成字符串,使用时再用JSON.parse
进行解析。
(2). 不同点
1.两者的失效时间是不同的。
localStorage本身是不会失效的,即使关闭浏览器,下次再访问该网站仍然有效。localStorage没有提供直接设置失效时间的方法,我们需要使用一种特殊的策略来定期清除localStorage:
localStorage.setItem(“name”, JSON.stringify({
value: “carter”,
time: (new Date()).getTime() // 保存时间戳
}))
function getItem(key, maxAge){
let obj = localStorage.getItem(key);
if(obj){ // 获取变量值对象
obj = JSON.parse(obj);
}
// 存储时间小于最大生命周期时才读取该参数,否则将其清除
if((new Date()).getTime() - obj.time < maxAge){
return obj.value;
} else {
localStorage.removeItem(key);
return “”;
}
}
getItem(“name”, 60 * 60 * 1000); // 失效时间为1小时
简单来说,就是把保存localStorage的时间一同存储进去,取值的时候再手动判断是否超时。
但sessionStorage与页面会话是绑定的,当某个页面会话失效时,对应的sessionStorage就会被清除。需要注意的是,sessionStorage只在会话页面失效时才会失效,也就是说刷新页面或者通过某种方式恢复当前页面时(如点击浏览器的回退按钮,或使用浏览器的页面恢复功能),sessionStorage并不会失效,换句话说,当某个页面创建了sessionStorage之后,它就总是与其创建的sessionStorage共存亡。
2. 两者的有效范围不同。
在不跨域的情况下,localStorage可以跨页签生效,而sessionStorage仅在当前页签范围内有效。
这就是说,如果你新打开了一个与当前页面同域的页面,这个新页面会与当前页面共享localStorage,却不能共享sessionStorage。而如果你是在当前页面的iframe内打开的,并且没有跨域,那么localStorage和sessionStorage都是可以共享的。
3. indexedDB
尽管5M的空间已经相对较大了,但仍然无法满足所有的前端存储需求。
这是因为前端数据缓存对web站点的性能提升是巨大的(它可以有效减少http数据传输量,而这通常是导致网站卡顿的最主要因素),因此越来越多的站点倾向于在前端存储更多的数据。localStorage和sessionStorage无法满足这样的需求,因为一方面,它们的容量只有5M大小;另一方面,由于是非结构化存储,当数据量较大时,它们的操作速度不够快。
为此,HTML5规范推出了前端的事务型数据库indexedDB。它可以存储大量的结构化数据,具有几乎可以媲美后端数据库的读写性能(当然,从功能和容量上远不及后端数据库)。
使用indexedDB大概需要以下几个流程:
- 打开数据库:
var request = window.indexedDB.open(databaseName, version);
这样就可以打开或新建一个indexedDB数据库。当所传入的数据库名不存在时,就会新建一个数据库,否则将打开已有数据库。当省略了数据库版本号时,如果数据库已存在,则默认为当前版本,否则版本号为1
。
- 注册处理事件
调用open方法后,返回的是一个IDBRequest
对象,通过向其注册error
、success
和upgradenedded
事件,可以处理打开数据的结果。
error
表示数据库打开失败:
request.onerror = function(err){
console.log(“数据库打开失败:” + err);
}
success
表示数据库打开成功,此时可以执行数据库读操作:
request.onsuccess = function (event) {
let db = request.result;
console.log(‘数据库打开成功’);
};
upgradeneeded
表示数据库需要升级,不同于一般的后端数据库,indexedDB每次修改数据库的内容都必须升级数据库版本:
request.onupgradeneeded = function (event) {
let db = event.target.result;
}
需要注意的是,新建数据库的相关操作本身被归类为升级数据库版本,因此需要在upgradeneeded事件中进行:
request.onupgradeneeded = function (event) {
db = event.target.result;
var objectStore;
if (!db.objectStoreNames.contains(‘person’)) {
objectStore = db.createObjectStore(‘person’, { keyPath: ‘id’ });
}
}
- 执行数据的增删改查操作
由于工作中暂未用到过indexedDB,缺少实际使用经验,因此这里暂不详述。如果感兴趣,请参考阮一峰:浏览器数据库 IndexedDB 入门教程。
三、前端存储与后端存储的关系
我们上面所介绍的四类存储都属于前端存储,除了cookie之外,其他三个都是直接通过JavaScript来访问和操作的。
严格来说,除了cookie外,其他三类存储都不是绝对必要的,那我们为什么还需要前端存储呢?
答案是,减少http数据传输,提升网站性能。
为了便于理解,我们把访问网站的整个过程做一个比喻,它就像我们去图书馆读书一样。图书馆本身就是整个网站,书架就是我们所用的后端数据库,而书架上的书就是保存在数据库中的所有网站数据。
图书馆的图书管理系统就是网站提供的后台服务,它向用户提供办卡、检索、借阅、还书等服务。
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数软件测试工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年软件测试全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上软件测试开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注软件测试)
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
5%以上软件测试开发知识点,真正体系化!**
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注软件测试)
[外链图片转存中…(img-Do857zRx-1712919049664)]
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
更多推荐
所有评论(0)