cookie、localStorage、sessionStorage、token详细介绍
前端本地存储的方式有三种,分别是cookie、localStorage、sessionStorage。
一、cookie
1.1 cookie是什么?
http是一种无状态协议,就是一种不保存状态的协议,一个服务器不清楚是不是同一个浏览器在访问它。cookie的出现是为了解决前一种技术token的缺陷。为了解决http无状态的特点,会在请求中插入token,然后发送请求,告诉服务器,但是这种方式容易出错,所以cookie就出现了。
http协议中的cookie包括web cookie和浏览器 cookie,是服务器发送到web浏览器的一小块数据,保存在浏览器的一小段文本信息,浏览器进行存储并且下次发送请求的时候携带上cookie。浏览器每次向服务器发送请求都会携带这段信息。用于判断了两个请求是否来自于同一个浏览器。
cookie是一种浏览器管理状态的一个文件,它有name、value,Domain、path等等。
1.2 cookie原理
第一次访问网站,浏览器会发送一个请求,服务器响应这个请求,会将cookie放进响应请求中。
第二次访问网站,浏览器发送的请求带有cookie,服务器会辨别这个用户的身份,相应的服务器也可以修改cookie。
1.3 cookie不可跨域请求
知识点补充
Q1:什么是跨域?
A1:在浏览器环境下,跨域是指一个域下文档或脚本去请求另一个域下的资源。
Q2:什么是域?
A2:协议+域名+端口
正常情况下,如果我们通过ajax去请求另一个域的资源是不可行的,违背浏览器的同源策略,浏览器默认阻拦这种行为。
Q3:什么是同源策略?
A3:同源策略SOP(Same Origin Policy),Netscape公司1995年提出并且引入浏览器。浏览器最核心的安全策略。缺少安全策略浏览器容易受到XSS、CSFR等等的攻击。同源就是协议+域名+端口相同。
Q4:同源可以获得浏览器什么支持?
A4:获取cookie、localStorage;获取DOM和js对象;发送ajax请求
1.4 cookie的属性
(1)Name
cookie的名字,一个域名下绑定的cookie的name不能相同。如果是相同的name则会被覆盖。
(2)value
每个cookie拥有的属性,表示cookie的值。
由于cookie规定是名称/值是不允许包含分号,逗号,空格的,所以为了不给用户到来麻烦,考虑服务器的兼容性,任何存储cookie的数据都应该被URL编码。
(3)domain
cookie的域名。cookie绑定的域名,如果没有设置,自动绑定当前执行语句的的域。同一个域名下的二级域名也是不可以交换cookie的。
(4)path
path是默认属性’/',匹配web路由
路径设置/blog的时候,也会给/blog绑定cookie
//默认
www.baidu.com
//blog路径
www.baidu.com/blog
(5)Expires
expires是cookie的有效期。一般浏览器的cookie是默认存储的,关闭浏览器结束会话,cookie就会被删除。
如果想要cookie续存一段时间,可以通过设置expires有效期。
expires现在被Max-Age取代:Max-Age,是以秒为单位的,Max-Age为正数时,cookie会在Max-Age秒之后,被删除;当Max-Age为负数时,表示的是临时储存,不会生出cookie文件,只会存在浏览器内存中,且只会在打开的浏览器窗口或者子窗口有效,一旦浏览器关闭,cookie就会消失;当Max-Age为0时,删除cookie,因为cookie机制本身没有设置删除cookie,失效的cookie会被浏览器自动从内存中删除,所以,它实现的就是让cookie失效。
(6)secure
安全。http无状态无加密,不安全协议容易被攻击挟持。比如你在浏览页面的时候是不是会有小广告出来。这个secure属性为true的时候,这个时候的cookie只会在https和ssl等安全协议下传输。不能对cookie加密,绝对安全保证做不到。
(7)httpOnly
安全的 Cookie 需要经过 HTTPS 协议通过加密的方式发送到服务器。即使是安全的,也不应该将敏感信息存储在cookie 中,因为它们本质上是不安全的,并且此标志不能提供真正的保护。
作用:①会话 Cookie 中缺少 HttpOnly 属性会导致攻击者可以通过程序(JS脚本、Applet等)获取到用户的 Cookie 信息,造成用户 Cookie 信息泄露,增加攻击者的跨站脚本攻击威胁。
②HttpOnly 是微软对 Cookie 做的扩展,该值指定 Cookie 是否可通过客户端脚本访问。
③如果在 Cookie 中没有设置 HttpOnly 属性为 true,可能导致 Cookie 被窃取。窃取的 Cookie 可以包含标识站点用户的敏感信息,如 ASP.NET 会话 ID 或 Forms 身份验证票证,攻击者可以重播窃取的 Cookie,以便伪装成用户或获取敏感信息,进行跨站脚本攻击等。
1.5 js操作cookie
//document.cookie
//读取浏览器的cookie
console.log(document.cookie)
//写入cookie
document.cookie = 'myname = ;path = /;domain = ';
1.6 服务端设置cookie
服务端通过setCookie来设置cookie,设置多个就多写几个setCookie。请求携带cookie传送给后端。
1.7 cookie的应用
(1)会话管理
登录验证、购物车、游戏得分或者其他服务器应该记住的状态。
登录验证:用户在第一次登录某个网站时,要输入用户名密码,如果觉得很麻烦,下次登录时不想输入了,那么就在第一次登录时将登录信息存放在 cookie 中。下次登录时我们就可以直接获取 cookie 中的用户名密码来进行登录。浏览器将信息保存在cookie是加密,但是不是绝对安全,也有造成不安全的信息泄漏的可能。
购物车:类似于购物车性质的功能,第一次用户将某些商品放入购物车了,但是临时有事,将电脑关闭了,下次再次进入此网站,我们可以通过读取 cookie 中的信息,恢复购物车中的物品。现在基本很少用,都是存储在数据库中,通过查询数据库来恢复购物车信息。
(2)个性化定制
用户的个性化定制主题,用户的偏好
(3)追踪
记录分析用户行为。Cookie曾经是客户端存储数据的唯一方式,如今改进用API。cookie每个请求都会携带会大大降低性能,尤其是对于移动数据的链接。
(4)页面传值
在实际开发中,我们往往会通过一个页面跳转到另外一个页面。后端服务器我们可以通过数据库,session 等来传递页面所需要的值。但是在浏览器端,我们可以将数据保存在 cookie 中,然后在另外页面再去获取 cookie 中的数据。cookie的数据具有时效性,注意过期日期不然会造成数据混乱。
1.8 cookie两种类型—会话cookie和永久性cookie
cookie有两种类型,分类取决于是否含有到期日期。
①一种是Session Cookies:会话cookie存储在内存,浏览器关闭cookie永久丢失。
②一种是Persistent Cookies:永久性cookie存储在磁盘,有效期到了将从磁盘中删除。
会话cookie
客户端关闭,数据删除,永久丢失。没有指定的Expires/Max-Age指令,存储在内存。
ps:Web浏览器可以让会话还原,可以让大多数会话cookie数据保持永久性,像浏览器永远没有关闭一样。
永久性cookie
客户端关闭,数据不会删除。当Expires或者Max-Age过期,才会删除数据,存储在磁盘。
1.9 cookie禁用
cookie可能被禁用,当用户非常注重隐私的时候,可以禁用浏览器的cookie功能。比如SessionID通过cookie存储在客户端,如果cookie被禁用,必然会造成Session使用的影响。
解决方法:URL重写
①servlet中涉及客户端输出页面元素的时候,在相应的请求地址外面加一层方法,response.encodeURL(‘URL’);为请求地址添加JSESSIONID的值。
②servlet跳转页面,使用response.encodeRedirectURL(‘URL’),为请求地址添加JSESSIONID的值。
1.10 总结
(1)cookie可能被禁用。当用户非常注重个人隐私的时候,浏览器cookie可以被禁用。
(2)cookie与浏览器相关。cookie是不能跨域请求的,访问同一个页面,不同浏览器之间保存的cookie也是不能相互访问的。cookie同一个浏览器的同源下是可以公用的,和是不是同一个页签没有关系。
(3)cookie可能被删除。每个cookie都是硬盘中的文件,因此可能被用户删除。
(4)cookie安全性不高。所有的cookie都是以纯文本形式记录在文件中,如果要保存加密信息,最好实现经过加密处理。
过渡
cookie可用于传递少量的数据,是一个在客户端和服务器之间来回传送文本值的内置机制,cookie只能传送很小的数据并且需要在客户端和服务器之间频繁传送时,cookie才有意义。那么如果需要在客户端保存大量的数据该怎么办呢?这时候就要用到另一种本地存储技术Web storage,web storage本地存储可以在客户端保存大量的数据。
HTML5提供了2种API:sessionStorage会话存储、localStorage本地存储
cookie完全是服务端可以操作的数据,sessionStorage和localStorage完全是浏览器端可以操作的数据。
二、sessionStorage
2.1 什么是sessionStorage
2.2 sessionStorage属性
sessionStorage的属性有Key和Value,保存了大量的数据。
2.3 失效时间
sessionStorage的生命周期仅在当前会话有效。sessionStorage引入了“浏览器窗口的概念”。sessionStorage在同源窗口中始终存在数据,只要浏览器窗口没有关闭,刷新或者重新进入页面数据依然存在。关闭浏览器窗口后数据会被删除。再次独立打开同一个窗口同一个页面,sessionStorage也是不一样。
2.4 存储的位置
sessionStorage都保存在客户端,一般不与服务器进行通信交互。
2.5 存储的大小
sessionStorage存储数据大小一般是5MB
2.6 存储内容的类型
sessionStorage只能存储字符串类型,对于复杂对象可以使用ECMAScript对象的stringify和parse处理。
2.7 获取方式
//sessionStorage
window.sessionStorage
2.9 sessionStorage的应用
敏感账号一次性登录
三、localStorage
3.1 什么是localStorage
3.2 localStorage的属性
localStorage的属性有Key和Value,保存了大量的数据。
3.3 失效时间
localStorage的生命周期是永久的,关闭页面或者浏览器之后localStorage中的数据也不会消失。localStorage删除数据要手动删除,否则数据永远不会消失。
3.4 存储的位置
localStorage都保存在客户端,一般不与服务器进行通信交互。
3.5 存储的大小
localStorage存储数据大小一般是5MB
3.6 存储内容的类型
localStorage只能存储字符串类型,对于复杂对象可以使用ECMAScript对象的stringify和parse处理。
3.7 获取方式
//localStorage
window.localStorage
3.8 localStorage的应用
常用于长期登录、判断是否已登录、适合长期保存在本地的数据。
3.9 手写会过期的localStorage
惰性删除、定时删除
惰性删除:某个键值过期后,该键值不会被马上删除,而是等到下次被使用的时候,才会被检查到过期,此时才能得到删除。
缺点:惰性删除已经实现可过期的localStorage缓存,但是也有明显的缺点。如果一个key一直没有被用到,就不会被及时检查,即使过期了也一直存在localStorage。
const lsc = (() => {
const prefix = 'one_more_lsc_';
/**
* 增加一个键值对数据
* @param key 键
* @param val 值
* @param expires 过期时间,单位为秒
*/
const set = (key, val, expires) => {
key = prefix + key;
val = JSON.stringify({ val, expires: new Date().getTime() + expires * 1000 });
localStorage.setItem(key, val);
};
/**
* 读取对应键的值数据
* @param key 键
* @returns {null|*} 对应键的值
*/
const get = (key) => {
key = prefix + key;
let val = localStorage.getItem(key);
if (!val) {
return null;
}
val = JSON.parse(val);
if (val.expires < new Date().getTime()) {
localStorage.removeItem(key);
return null;
}
return val.val;
};
return { set, get };
})();
export default lsc;
定时删除:每隔一段时间执行一次删除操作,并通过限制删除操作执行的次数和频率,来减少删除操作对CPU的长期占用。另一方面定时删除也有效的减少了因惰性删除带来的对localStorage空间的浪费。
每隔一秒执行一次定时删除,操作如下:
①随机测试20个设置了过期时间的key
②删除所有发现的已过期的key
③若删除的key超过5个则重复步骤1,直到重复500次
const lsc = (() => {
let prefix = 'one_more_lsc_';
let list = [];
const init = () => {
let keys = Object.keys(localStorage);
let reg = new RegExp('^' + prefix);
let temp = [];
for (let i = 0; i < keys.length; i++) {
if (reg.test(keys[i])) {
temp.push(keys[i]);
}
}
list = temp;
};
const check = () => {
if (!list || list.length === 0) {
return;
}
let checkCount = 0;
while (checkCount < 500) {
let expireCount = 0;
for (let i = 0; i < 20; i++) {
if (list.length === 0) {
break;
}
let index = Math.floor(Math.random() * list.length);
let key = list[index];
let val = localStorage.getItem(list[index]);
if (!val) {
list.splice(index, 1);
expireCount++;
continue;
}
val = JSON.parse(val);
if (val.expires < new Date().getTime()) {
list.splice(index, 1);
localStorage.removeItem(key);
expireCount++;
}
}
if (expireCount <= 5 || list.length === 0) {
break;
}
checkCount++;
}
};
init();
setInterval(check, 1000);
return { init, check };
})();
export default lsc;
3.10 localStorage的限制
(1)IE8以上版本才支持localStorage这个属性
(2)目前主流浏览器中都会把localStorage的值类型限定为string类型,这个对我们日常比较常见的JSON对象类型需要一些转换
(3)localStorage在浏览器的隐私模式下不可读取
(4)localStorage本质上是对字符串的读取。如果读取内容多的话会消耗内存空间,导致页面卡。
(5)localStorage不会被爬虫爬取到数据
token
- cookie 是 http 规范,token 是自定义传递的。
- cookie 没有被浏览器存储,下一次请求时便会带上,而 token 需要自己存储在浏览器,下一次请求时再请求头中带上。
- token 默认没有跨域限制。
1.场景
用户登录成功后, 需要反复到服务器获取敏感数据,服务器对每次请求都要验证是哪位用户发送的, 且用户是否合法, 需要反复查询数据库, 对数据库造成过大压力
2.什么是token
作为计算机术语时,是“令牌”的意思
Token是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后,服务器生成一个Token便将此Token返回给客户端,以后客户端只需带上这个Token前来请求数据即可,无需再次带上用户名和密码
3.token是用来干嘛的
使用token机制的身份验证方法,在服务器端不需要存储用户的登录记录
大概的流程:
客户端使用用户名和密码请求登录(服务器–后端)
服务端收到请求,验证用户名和密码
验证成功后,服务端(后台)会生成一个token,然后把这个token发送给客户端(前端)
客户端收到token后把它存储起来,可以放在cookie或者Local Storage(本地存储)里
客户端每次向服务端发送请求的时候都需要带上服务端发给的token(客户端–前端)
服务端收到请求,然后去验证客户端请求里面带着token,如果验证成功,就向客户端返回请求的数据
这个token必须在每次请求时传递给服务器,应该保存在请求头里,另外服务器要支持CORS(跨域资源共享)的策略
token使用小结
前端登陆的时候向服务器发送请求,服务器验证成功,会生成一个token
前端会存储这个token,放在session或cookie中,用于之后的业务请求身份验证
拿着这个token,可以在当前登录的账号下进行请求业务,发送请求时,token会放在请求头里,服务器收到这个业务请求,验证token,成功就允许这个请求获取数据
token可以设置失效期,超时需要重新登录
4.优势 (相较于cookie)
支持跨域访问: cookie是不允许跨域访问的, token支持
无状态: token不需要服务器保存任何相关信息. token自身就携带所有值
去耦: 不需要绑定特定的身份验证方案
更适合移动应用: cookie不支持手机端访问
基于标准化:JWT
5.缺陷
占带宽: 比session_id 大, 消耗更多的流量
无法在服务端注销: 很难解决劫持问题
性能问题: JWT标准消耗更多的 CPU 资源