我们都知道,作为一名前端开发,或多或少在开发的过程中因为各种各样的需求,需要在前端存储一些数据,比如登录验证,可能会用到cookie,或者localStorage存储token,然后请求手动带上。所以我们很需要搞清楚前端存储有哪些方法,以及我们该如何去使用这些我们已经司空见惯的单词(Cookie、sessionStorage和localStorage)
HTTP Cookie,通常直接叫做cookie,最初是在客户端用于存储会话信息的。该标准要求服务器对任意HTTP请求发送Set-Cookie HTTP头作为响应的一部分,其中包含会话信息。
说的直白一点,一般就是用来登录验证,在发送登录请求的以后,服务端在返回的响应头中设置Set-Cookie,并设置其值。并且cookie遵循浏览器同源策略,在不同源的页面中是访问不到当前页面的cookie的。如果可以的,就能拿到cookie伪造请求进行XSS和CSRF攻击。
就像上图所示,在响应头中有了Set-Cookie,并设置了服务端返回的相应的值,这个时候我们在查看当前页面的Application中的cookie,发现其中已经有了刚才返回的cookie。会话cookie一般不会存储在硬盘里,而是保存在内存中,如果是设置了过期时间,浏览器会把cookie保存在硬盘中。
就上图中,我们可以看见返回的Set-Cookie
中有时间,所以当前返回的cookie是保存在硬盘中的。cookie会随着页面发送的请求再带回到服务端,然后服务端判断cookie的值,进而判断当前的登录状态。 既然我们刚才设置的cookie是有有效时间的,所以在有效时间之前,我们不管怎么操作页面(关闭标签页或者浏览器),我们只要打开页面发送请求,就会默认我们已经是登录状态,不需要再次登录。
上图就是携带cookie的请求,这不是前端手动在请求中携带上的,是浏览器的自主行为。
刚才我们说了,只要服务端在请求回来的响应头中设置了Set-Cookie
的值,服务端就在浏览器中种下了cookie,以后的每个请求都会携带上这个cookie,但是也有个别情况发送的请求是不会默认携带cookie。
Cors跨域请求和fetch请求默认是不携带cookie的
我们不管jQuery中发送的jsonp请求,因为严格意义上讲,jsonp不算是发送请求后端返回数据的形势。我们现在只讨论发送的json请求。在相同域下,我们发送的Ajax请求⬇️
$.ajax({
type: 'post',
url: '/person/detail',
dataType: 'json',
data: {
id: 1
},
success: function (res) {},
error: function(e) {}
})
如果我们请求的是一个不同域下的接口,我们不考虑反向代理的情况,因为反向代理理论上还是访问相同域的接口。下面是如果我们使用Cors解决跨域的时候⬇️
$.ajax({
type: 'post',
url: '/person/detail',
dataType: 'json',
data: {
id: 1
},
xhrFields: {
withCredentials: true // 如果是Cors解决的跨域,我们请求接口的域和我们页面所在域是不同域,所以需要添加这个属性值
},
success: function (res) {},
error: function(e) {}
})
下面是我们在vue或者react库中经常用到一个请求库——Axios,Axios发送Cors跨域请求,默认也是不会带上cookie的⬇️
axios({
method: 'post',
url: '/person/detail',
data: {
id: 1,
}
});
上面是正常的同域请求,下面我们来看怎么发送Cors请求
axios({
method: 'post',
url: '/person/detail',
data: {
id: 1,
},
withCredentials: true, // 设置了这个值,我们我就可以发送Cors请求了,这个值默认不设置的话是false
});
fetch是javascript提供的一个比较底层的API,让我们可以方便的发起fetch请求,但是fetch请求现在看来,只是一个底层API,虽然相对于原生Ajax请求方便一些,但是Ajax已经被各种库封装的很方便使用了,可fetch就相形见绌了。就我们现在来看,fetch不仅仅是在发送Cors请求的时候不懈怠cookie,而是默认情况下,fetch什么情况都不会从服务端发送或接收任何cookied,我们先来看正常请求⬇️
fetch('/person/detail', {
method: 'POST',
body: JSON.stringify({id: 1}),
headers: {
'content-type': 'application/json'
},
})
上面我们就发送了一条fetch请求,然后我们需要请求凭证,需要有cookie怎么办呢⬇️
fetch('/person/detail', {
method: 'POST',
body: JSON.stringify({id: 1}),
credentials: 'include', // 强制带上凭据头,携带上cookie
headers: {
'content-type': 'application/json'
},
})
下面是一个cookie的构成
我们通过js是很方便获取cookie的只需要document.cookie,我们就能获取到当前页面的cookie。
我们发现我们获取到的cookie是一长串字符串,而我们在Application看到是已经经过序列化的cookie了。我们既然获取到了cookie,剩下的就是自己进行序列化处理,操作字符串了,我就不多赘述了。
我们更改cookie的话,如果有相同值,会覆盖,如果没有,会创建新的
通过上面我们能知道document.cookie是如何获取和更改cookie值的,不管cookie保存了什么,都会跟随请求一并带到服务端去。如果我们需要频繁操作cookie的值,我们可以自己封装操作cookie的get、set方法。
cookie就这些,毕竟我们现在应该不会大量使用cookie去完成前端数据存储的工作,一是存储的数量太小,二是请求都会带上,浪费带宽。也因为请求会带上cookie,所以中间穿插了一些请求携带cookie的点。
Web Storage 克服了由cookie代来的一些限制,当数据需要被严格控制在客户端上时,无须持续地将数据发回服务器。Web Storage的两个主要目的:
sessionStorage
和localStorage
共同的Storage Api
sessionStorage和localStorage同属于Web Storage,虽然他们的有效时间不同,但是有着相同的方法供开发者使用
// clear方法,可以删除sessionStorage中所有的值
sessionStorage.clear(); // 清除所有sessionStorage中的数据
localStorage.clear(); // 清除所有localStorage中的数据
// getItem(name) 根据指定的名字name获取对应的值
var name = sessionStorage.getItem('name'); // 获取key为name的value
var name = localStorage.getItem('name'); // 获取key为name的value
// 当然,我们也可以不这么着获取storage中的值,也可以像下面这样获取值
var name = sessionStorage.name; // 获取key为name的value
var name = localStorage.name; // 获取key为name的value
// key(index) 可以获取到index位置处的值的名字
var key = sessionStorage.key(0); // 获取到了sessionStorage中排在第一个的值的key,比如刚才的’name‘
var key = localStorage.key(0); // 获取到了localStorage中排在第一个的值的key,比如刚才的’name‘
// 获取到了排在第一位的key值,我们就可以根据这个key获取对应的value了
var value = sessionStorage.getItem(key); // 这样我们就获取到了排在第一位的name的value值
var value = localStorage.getItem(key); // 这样我们就获取到了排在第一位的name的value值
// removedItem(name) 删除由name指定的键值对
sessionStorage.removedItem('name'); // 删除了key为name的value
localStorage.removedItem('name'); // 删除了key为name的value
// 我们也能使用删除对象中属性的delete方法来删除
delete sessionStorage.name;
delete localStorage.name;
// setItem(name, value) 为指定的name设置一个对应的值
sessionStorage.setItem('name', 'zhanwuzha'); // 在sessionStorage中存了一个name,值为zhanwuzha
localStorage.setItem('name', 'zhanwuzha'); // 在localStorage中存了一个name,值为zhanwuzha
// 我们也可以使用另一种方法来设置
sessionStorage.name = 'zhanwuzha'; // 在sessionStorage中存了一个name,值为zhanwuzha
localStorage.name = 'zhanwuzha'; // 在localStorage中存了一个name,值为zhanwuzha
以上就是Web Storage中的方法,涵盖了增删改查。delete操作符在WebKit中无法删除数据,所以我们还是使用removeItem()
方法吧;
Web Storage中保存的数据,不会跟随请求一同发回服务器,这是跟cookie最大的区别,并且是按键值对来保存数据的,虽然cookie
也是键值对,但是是类似'name=zhanwuzha&age=16'
这样的字符串,还需要在进一步处理。
sessionStorage对象存储特定于某个会话的数据,也就是该数据只保持到浏览器关闭。这个对象就像会话cookie,也会在浏览器关闭后消失。存储在sessionStorage中的数据可以跨越页面的刷新而存在,同时如果浏览器支持,浏览器崩溃并重启之后依然可用(Firefox和WebKit都支持,IE则不行)
sessionStorage在满足上面storage共同的方法之外,它的使用是绑定在某个会话的:
遵循浏览器的同源策略,不同源的根本就访问不到
符合同源策略的,必须是同一个会话即使是相同地址,不是同一个会话也不行