前言
大概是我的业务领域比较狭窄的原因,我总是会听说cookie,却很少在实际的开发中应用或者实践过它,今天刚好看到<<JavaScript高级程序设计第三版>>的数据存储部分,说到了cookie,这里就对cookie做一个深入访谈,希望和我一样对cookie似曾相识的朋友可以真正的熟悉cookie,并学会利用cookie来服务我们的业务.^_^^_^
Cookie
定义
cookie,是服务器为了辨别用户身份,进行session跟踪而存储在用户本地终端上的数据(通常经过加密).
限制
域名限制
因为cookie一般用于与服务器进行交互,所以它一般存放在对应的域名下.当设定了一个cookie后,再给创建它的域名发送请求时,都会包含这个cookie,这个限制确保了储存在cookie中的信息只能让批准的接受者访问,而无法被其他域访问.
个数限制
由于cooki是存储在客户端计算机上的,还加入了一些限制确保cookie不会被恶意使用,同时不会占据太多磁盘空间.每个域的cookie总数是有限的,不过浏览器之间各有不同.
- IE7和之后的版本每个域名最多50个.
- Firefox限制每个域最多50个cookie
- Opera限制每个域最多30个cookie
- Safari 和Chrome 对每个域的cookie数量没有硬性规定.
当超过单个域名限制之后还要在设置cookie,浏览器会清除以前设置的cookie.IE和Opera会删除最近最少使用过的cookie.所以考虑cookie限制非常重要,避免出现不可预期的后果.
尺寸限制
浏览器中对于cookie的尺寸也有限制,大多数浏览器是4KB的长度限制,尺寸限制影响一个域下所有的cookie,而并非每个cookie单独限制.
如果你尝试创建查过最大限制的cookie,那么该cookie会被悄无声息地丢掉.
cookie的构成
cookie由浏览器保存的以下几块信息构成.
- 名称(name): 一个唯一确定cookie的名称.
- 值(value): 存储在cookie中的字符串值.
- 域(domain): cookie对于哪个域是有效的,控制只有向该域发送的请求才会包含这个cookie.
- 路径(path): 对于指定域中的哪个路径,应该向服务器发送cookie.
- 失效时间(expires): 表示cookie何时会被删除的时间戳,没有设置则默认是浏览器会话结束时,即将所有cookie删除,若设置的失效日期是以前的时间,则cookie会被立刻删除.
- 安全标志(secure): 制定后,cookie只有在使用SSL链接的时候才会发送到服务器,即https请求才可以发送cookie.
注意发送cookie的时候只会发送cookie的名和值才会被发送,其他值只会cookie信息的描述.
cookie的使用
使用场景
常用场景: cookie一般用来做登录验证,用户登陆的时候讲用户名和密码传入到服务器端,服务器会返回将用户相关的认证信息,然后由服务器将这些信息写入cookie或者由前端使用js操作cookie将这些信息写入到cookie中(如果服务器通过Set-Cookie的方式直接写入则不需要前端的参与,前端是无感知的),登陆成功以后的用户在该域名下的访问都会在请求中发送cookie,作为该用户的身份标识.我们这里主要讨论的是前端使用js操作cookie的情况.
不常用场景: 我们也可以用js操作cookie,在cookie上存储我们临时需要的用于页面交互的变量,这个时候cookie就充当了sessionStorage或者localStorage的角色.
操作cookie
由于JavaScript中读写cookie不是非常直观,常常需要写一些函数来简化cookie的功能.基本的操作有三种: 读取,写入,删除;
说明: 我不知道看这篇文章的朋友是不是了解这些操作cookie的方法,如果不了解,我建议你先想一想,然后尝试着自己去写,然后感兴趣的话再来看看我的代码,也可以分享到评论区,我们一起来看看这些实现方法的优劣,不知道不同思想的碰撞会不会擦出奇妙的火花呢? 很期待奥~
封装的操作cookie的代码如下:
const CookieUtil = {
// 获取cookie 接受的参数 cookie的名称
get: function(name) {
var cookieName = encodeURIComponent(name) + "=",
cookieStart = document.cookie.indexOf(cookieName),
cookieValue = null;
if(cookieStart !== -1) {
var cookieEnd = document.cookie.indexOf(";",cookieStart);
if(cookieEnd == -1) {
cookieEnd = document.cookie.length;
}
cookieValue = decodeURIComponent(document.cookie.substring(cookieStart + cookieName.LENGTH, cookieEnd));
}
return cookieValue;
},
// 设置cookie, 接收参数: cookie的名称, cookie的值,
// 可选的用于执行cookie何时应被删除的Date对象,cookie的可选的URL路径, 可选的域和是否要添加secure标志的布尔值
set: function (name, value, expires, path, domain, secure) {
var cookieText = encodeURIComponent(name) + "=" + encodeURIComponent(value);
if(expires instanceof Date) {
cookieText += "; expires=" + expires.toGMTString();
}
if(path) {
cookieText += "; path=" + path;
}
if(domain) {
cookieText += "; domain=" + domain;
}
if(secure) {
cookieText += "; secure";
}
document.cookie = cookieText;
},
// 删除cookie的方法, 接收的参数: 要删除的cookie的名称,可选的路径参数,可选的域参数和可选的安全参数
unset: function (name, path, domain, secure) {
// 将某个cookie的过期时间早于当前时间,则会被立刻删除,该方法设置失效时间为1970年1月1日
this.set(name, "", new Date(0), path, domain, secure);
}
}
// 设置cookie
CookieUtil.set("name", "Nicholas");
CookieUtil.set("book", "Professional JavaScript");
// 读取cookie的值
CookieUtil.get("name");
CookieUtil.get("book");
// 删除cookie
CookieUtil.unset("name");
CookieUtil.unset("book");
子cookie
为了绕开浏览器的单域名下的cookie数限制,一些开发人员使用了一种成为子cookie的改变,子cookie是存放在单个cookie中的更小段的数据,通常是多个名称值对的形式.子cookie对常见的格式如下所示:
namename1=value1&name2=value2&name3=value3&name4=value4&name5=value5
子cookie一般也以查询字符串的格式进行格式化,然后这些值可以使用单个cookie进行储存和访问,而非对每个名称-值对儿使用不同的cookie存储,最后网站或者web应用程序可以无需大到单域名cookie上限也可以存储更加结构化的数据.
为了更好的操作子cookie,必须建立一系列新方法,子cookie的解析和序列化会因子cookie的期望用途而略有不同并更加复杂些,例如,要获得一个子cookie,首先要遵循与获得cookie一样的基本步骤,但是在解码cookie值之前,需要操作字符串,遍历数组之类的操作来找出子cookie的信息.
说明: 我不知道看这篇文章的朋友是不是了解这些操作cookie的方法,如果不了解,我建议你先想一想,然后尝试着自己去写,然后感兴趣的话再来看看我的代码,也可以分享到评论区,我们一起来看看这些实现方法的优劣,不知道不同思想的碰撞会不会擦出奇妙的火花呢?
操作子cookie的方法如下:
// 操作子cookie的一组方法
var SubCookieUtil = {
// 获取cookie, 接收两个参数,cookie名和子cookie名
// 如果不穿子cookie名,则是普通的获取方法,如果传了,则取对应子cookie名的value.
get: function (name, subName) {
var subCookies = this.getAll(name);
if(subCookies) {
return subCookies[subName];
} else {
return null;
}
},
// 判断如果cookie中name对应的value不包含子cookie,
// 则返回解码后的cookieValue,如果包含子cookie,则返回处理后的result对象
getAll: function (name) {
var cookieName = encodeURIComponent(name) + "=",
cookieStart = document.cookie.indexOf(cookieName),
cookieEnd,
result={},
cookieValue= null,
i,len,subCookies='',
parts = [];
if(cookieStart !== -1) {
cookieEnd = document.cookie.indexOf(";", cookieStart);
if(cookieEnd == -1) {
cookieEnd = document.cookie.length;
}
cookieValue = document.cookie.substring(cookieStart + cookieName.length, cookieEnd);
if(cookieValue.length > 0) {
if(cookieValue.indexOf("&") > -1) {
subCookies = cookieValue.split("&");
console.log("get subCookies",subCookies);
for(i = 0,len = subCookies.length; i < len; i++) {
parts = subCookies[i].split("=");
result[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]);
}
} else {
parts = cookieValue.split("=");
result[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1])
}
return result;
}
}
return null;
},
// 同样的,要设置子cookie,也有新的set方法
set: function(name, subName, value, expires, path, domain, secure) {
var subCookies = this.getAll(name) || {};
subCookies[subName] = value;
this.setAll(name, subCookies, expires, path, domain, secure);
},
setAll: function(name, subCookies, expires, path, domain, secure) {
var cookieText = encodeURIComponent(name) + "=",
subCookieParts = [],
sub, result;
// 将subCookies对象里的cookie值对编码,并放进subCookieParts数组中
for(sub in subCookies) {
if(subCookies.hasOwnProperty(sub)) {
subCookieParts.push(encodeURIComponent(sub)+ "=" + encodeURIComponent(subCookies[sub]));
}
}
if(subCookieParts.length > 0) {
cookieText += subCookieParts.join("&");
if(expires instanceof Date) {
cookieText += "; expires=" + expires.toGMTString();
}
} else {
cookieText += "; expires=" + (new Date(0)).toGMTString();
}
if(path) {
cookieText += "; path=" + path;
}
if(domain) {
cookieText += "; domain=" + domain;
}
if(secure) {
cookieText += "; secure";
}
document.cookie = cookieText;
},
// 删除cookie 删除单个cookie
unset: function(name, subName, path, domain, secure) {
var subCookies = this.getAll(name);
subCookies[subName] ? delete subCookies[subName] : '';
this.setAll(name, subCookies, null, path, domain, secure);
},
//删除cookie 删除多个cookie
unsetAll: function (name, path, domain, secure) {
this.setAll(name, null, new Date(0), path, domain, secure);
}
}
// 假设 document.cookie = "data=name=Nicholas&book=Professional%20JavaScript"
// 设置两个cookie
SubCookieUtil.set("xiaosisi", "name", "Nicholas");
SubCookieUtil.set("xiaosisi", "book", "Professional JavaScript");
SubCookieUtil.set("xiaosisi", "sisisi", "撕撕撕");
// 设置全部子cookie和失效日期
SubCookieUtil.setAll("xiaosisi", {name: "Nicholas", book:"Professional JavaScript", sisisi: "撕撕撕"}, new Date("2018-10-25"));
// 修改名字的值,并修改失效日期
SubCookieUtil.setAll("xiaosisi", "name", "MIrascl", new Date("2018-11-25"));
// 删除名为sisisi的子cookie
SubCookieUtil.unset("xiaosisi", "sisisi");
// 删除整个cookie
SubCookieUtil.unsetAll("xiaosisi");
总结
关于cookie有两点需要注意的地方:
第一: 由于所有的cookie都会由浏览器作为请求头发送,所以在cookie中存储大量信息会影响到特定域的请求性能,cookie信息越大,完成对服务器请求的时间也就越长.尽管浏览器对cookie的大做了限制,不过最好还是尽可能在cookie中少存储信息,以免影响性能.
第二:一定不要在cookie中存储重要和敏感的数据.cookie的存储不是很安全,其中包含的任何数据都可以被他人访问,重要的用户信息不建议存储在cookie里.
如果读者们有关于cookie的比较好的使用策略欢迎在评论区留言或者私信我奥~共同进步是最让人开心的事儿呢~~~
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。