客户端存储之cookie
什么是cookie和为什么有cookie
- 什么是cookie
cookie是指web浏览器存储的少量数据(注意:这些数据是由服务器给浏览器的,然后由浏览器存储保管)。这些数据是与你访问的页面或站点相关的
- 为什么会有cookie
首先我们应该知道——HTTP协议是无状态的
什么是协议的状态——协议的状态是指:下一次传输可以记住上一次传输的信息的能力。从传统WEB上看:无状态是指,当浏览器发送请求给服务器的时候,服务器响应,但是同一个浏览器再发送请求给服务器的时候,他会响应,但是他不知道你就是刚才那个浏览器,简单地说,就是服务器不会去记得你,所以是无状态协议。本质是:HTTP1.0是短连接的(这里先忽略HTTP1.1的keep alive吧),请求响应后,断开了TCP连接,下一次连接与上一次无关
然后,为了识别不同的请求是否来自同一客户(或者说间接地使HTTP协议有状态),便引入了HTTP会话机制
而cookie就是实现会话的一种机制(因此,cookie实际上存储的是会话信息)
会话就是:TCP的三次握手就创建了一个会话,TCP关闭连接就是关闭会话,这就是一次会话
cookie是怎么工作的
cookie标准要求服务器对任意HTTP请求发送Set-Cookie头,作为响应的一部分
浏览器会存储这些会话信息,并在之后访问相同的页面或站点时,通过为每个请求添加Cookie头,将上一次存储的会话信息返回给服务器
服务器端脚本读取返回的Cookie信息,并作出相关响应
这样通过cookie便间接地使HTTP有了状态
我们平时都见过,登录时自动记录账号。我们就以此为例,来阐述cookie的工作流程:
注:每一个小圆点,就代表一步
- 当你填好用户名与密码后,点击登录按钮,向服务器发出一个登录请求
- 服务器收到请求,并创建一个保存了用户名和其他与本次请求相关的状态信息的cookie,然后将该cookie信息放入响应头中,并与响应体一同传回给浏览器(响应头中的Set-Cookie即为浏览器传回的cookie)
- 浏览器读取响应头中的cookie信息,并以文本文件的形式保存到计算机中(前提是浏览器允许保存cookie信息)
- 下一次你再访问本登录页面时,浏览器自动将对应的保存在本地的cookie信息取出,并以请求头的形式发送给服务器(请求头中的Cookie即为发送的cookie),然后服务器返回的登录页中的脚本会读取cookie中的用户名信息,将其设置在输入框中(这一步我不太确定想的是否正确)
注意:cookie由服务器端设置,保存在客户端
如果你还是疑惑,可以参考这篇文章:
https://www.cnblogs.com/andy-zhou/p/5360107.html
cookie的组成
这儿先用一张图展示(chrome浏览器中展现的)cookie的组成部分
- Name与Value
这个很好理解,Name对应该cookie的名,Value对应该cookie的值(似乎有点废话)。如:
document.cookie = 'age=19';
中‘age’对应Name,19对应Value
- Domain(域名)
用于确定该cookie对于哪些域是有效的。所有向这些域发送的请求都会包含这个cookie信息(当然:Path也要允许才行)。该值可以是子域(如:www.baidu.com),也可以是父域(如:baidu.com——则该cookie对于其下所有的子域都有效)。如果没有明确的设定,那么这个域默认为设置cookie的那个域
子域能访问父域的cookie,父域不能访问子域的cookie;同级的域之间也不能互相访问各自的cookie
cookie满足同源策略
- Path(路径)
设置cookie路径,从而确定域中的哪些路径应该像服务器发送cookie。(实际同Domain差不多)
默认为当前文件位于服务器中的路径(即url中域名后面由‘/’展现的路径——默认状态),可以人为修改默认值
注意:
子路径(目录)可以访问祖先路径(目录)中的cookie,而祖先路径(目录)不能访问子路径(目录)中的cookie
而判断是子路径还是祖先路径。需根据path的值,而无论在文件夹中的实际位置如何
如:
D:\wampserver\wamp\www\temp.html(默认path为/)
document.cookie = ‘age=19’;
D:\wampserver\wamp\www\test\temp.html(默认path为/test)
document.cookie = ‘name=德洛丽丝’;
现在我们采用path的默认路径。问,在test下的temp.html中能访问www下的temp.html的cookie吗?
我们先运行www文件夹下的temp.html,再运行test下的temp.html,你会发现test下的temp.html有两个cookie,其中一个即为来自www下temp.html的cookie
- Expires/Max-Age
设置cookie的删除时间。默认情况下——在浏览器会话结束时即将所有cookie删除(‘会话’前面已经说了)。也可自己设置(这个值是GMT格式——Wdy, DD-Mon-YYYY HH:MM:SS GMT——通过Date对象中的toUTCString()方法)
值为负数时,表示关闭窗口后cookie即失效(此时cookie存在于内存中,不会被写入本地文件);值为0表示不保存该cookie,立即删除。设置的是以前的时间,cookie也会立即删除
因此,我们常常设置这个属性的值为0或负数来达到删除cookie的操作
尤其注意:除了Name、Value以外的像Domain、Path等其它组成部分都是服务器给浏览器的关于本次cookie的描述。因此,这些参数并不会作为Cookie头的一部分由浏览器发送给服务器。只有名值对才会发送给服务器
使用JS脚本操作cookie
主要就是cookie的增、删、改、查
- 增
使用‘document.cookie’来增添cookie
<script>
document.cookie = 'name=德洛丽丝';
document.cookie = 'age=19';
</script>
关于增操作需要注意的地方:
- 当我们要设置多个cookie时,需要多次‘document.cookie’,不能一次性全设置,例如这样
document.cookie = 'age=19;name=德洛丽丝';//这是错误的
要是以这种错误的方式设置,则结果便是下面这样
可见,只有age被设置上了。这是因为,在设置cookie时,只会将第一个等式视为cookie,后面的等式都视为描述此cookie的属性(当然,以为是自定义的,所以这些属性不会被展现,实际可能根本不会被设置为属性,这个我也不太清楚)
- 相同的cookie,会值覆盖,不同的cookie不会值覆盖。如下:
<script>
document.cookie = 'name=德洛丽丝';
document.cookie = 'name=伯纳德';
</script>
那什么样的cookie才算是不同的cookie呢?只要‘Name、Domain、Path’这几个属性只要有一个不同,则cookie不同(三个属性都相同cookie才相同)。下面一一为你展现,这几个属性不同时的结果
关于Domain不同,无法演示,因为跨域了。。。
上述只是现象,关于背后的原因会在介绍‘Domain、Path’两个属性时叙述,你只需要记住什么情况下cookie不同就行了
3.在设置cookie时最好使用encodeURIComponent()编码,获取时再使用decodeURIComponent()解码
document.cookie=encodeURIComponent('name')+'='+encodeURIComponent('德洛丽丝');
- 删
cookie并不提供删除操作,因此若想删除某个cookie,则需要使用增添操作,添加一个‘相同的cookie’(Domain、Path、Name相同)并将其中的max-age设为0或负数。如:
document.cookie = 'name=德洛丽丝';
setTimeout(function(){
document.cookie = 'name=德洛丽丝;max-age=-1';
}, 1000);
//document.cookie = 'name=德洛丽丝;max-age=-1';或者直接这样删除(不用点击刷新按钮)
上述添加了一个cookie、1s后将该cookie删除
注意:这种删除方式需要你点击一下控制台的刷新按钮,不然cookie会一直显示出来,实际上你已经删除了
- 改
cookie并不提供改操作,因此若想修改某个cookie,则需要使用增添操作,添加一个‘相同的cookie’(Domain、Path、Name相同),但值不同
document.cookie = 'name=德洛丽丝';
setTimeout(function(){
document.cookie = 'name=伯纳德';
}, 1000);
注意点击刷新按钮
- 查
cookie并不提供查操作,因此你需要将本页面对应的所有cookie读出来(结果是字符串),然后对字符串进行处理,以提取cookie的值
直接使用‘document.cookie’便可以读取所有cookie
document.cookie = 'name=德洛丽丝';
document.cookie = 'age=30';
document.cookie = 'sex=女';
var cookieStr = document.cookie;//"name=德洛丽丝; age=30; sex=女"
var cookieArr = cookieStr.split('; ');
console.log(cookieArr[0].split('=')[0] + ':' + cookieArr[0].split('=')[1]);
cookie增、删、改、查操作的封装
var cookieOperation = {
add : function(name, value, time){//增或改
document.cookie = name + '=' + value + ';max-age=' + time;
return this;
},
check : function(name){
var cookieStr = document.cookie,
cookieArr = cookieStr.split('; '),
len = cookieArr.length;
for(var i = 0; i < len; i++){
if(cookieArr[i].split('=')[0] === name){
return cookieArr[i].split('=')[1];
}
}
},
remove : function(name){
return cookieOperation.add(name, '', 0);
}
};
cookie与web存储的比较
关于cookie的作用域与有效期是由path/domain、max-age决定的,文中也说了。更权威的可看
《JavaScript权威指南》——20.2.1节