1.前言
众所周知,在JS中处理cookie有些复杂,因为其操作cookie的接口相当不友好,即BOM的document.cookie
属性。这个属性的独特之处在于它会因为使用它的方式不同而表现出不同的行为。
- 当用来获取属性时,
document.cookie
返回当前页面可用的所有cookie的字符串,即一系列有分号分隔的键值对,并且所有键和值都是经过URL 编码的,所以必须使用decodeURIComponent()
来解码。 - 当用于设置值的时候,
document.cookie
属性可以设置为一个新的cookie 字符串。这个cookie 字符串会被解释并添加到现有的cookie 集合中。设置document.cookie
并不会覆盖cookie,除非设置的cookie 的名称已经存在。例如:document.cookie = "name=NanLiangReXue";
这段代码创建了一个叫name 的cookie,值为NanLiangReXue。
正是由于JavaScript 中操作cookie 不是非常友好,所以我们常常需要自己封装操作函数来简化操作cookie 的过程。
2.cookie的组成
在操作cookie之前,我们有必要先来看看cookie是由哪几部分构成的。
- 名称name:一个唯一确定cookie 的名称。cookie 名称是不区分大小写的,所以myCookie 和MyCookie被认为是同一个cookie。然而,实践中最好将cookie 名称看作是区分大小写的,因为某些服务器会这样处理cookie。cookie 的名称必须是经过URL 编码的。
- 值value:储存在cookie 中的字符串值。值必须被URL 编码。
- 域domain:cookie 对于哪个域是有效的。所有向该域发送的请求中都会包含这个cookie 信息。这个值可以包含子域(subdomain,如www.wrox.com),也可以不包含它(如.wrox.com,则对于wrox.com的所有子域都有效)。如果没有明确设定,那么这个域会被认作来自设置cookie 的那个域。
- 路径path:对于指定域中的那个路径,应该向服务器发送cookie。例如,你可以指定cookie 只有从http://www.wrox.com/books/ 中才能访问,那么http://www.wrox.com 的页面就不会发送cookie 信息,即使请求都是来自同一个域的。
- 失效时间expries:表示cookie 何时应该被删除的时间戳(也就是,何时应该停止向服务器发送这个cookie)。默认情况下,浏览器会话结束时即将所有cookie 删除;不过也可以自己设置删除时间。这个值是个GMT 格式的日期(Wdy, DD-Mon-YYYY HH:MM:SS GMT),用于指定应该删除cookie 的准确时间。因此,cookie 可在浏览器关闭后依然保存在用户的机器上。如果你设置的失效日期是个以前的时间,则cookie 会被立刻删除。
- 安全标志secure:指定后,cookie 只有在使用SSL 连接的时候才发送到服务器。例如,cookie 信息只能发送给 https://www.wrox.com,而http://www.wrox.com 的请求则不能发送 cookie。
以上每一个字段信息都作为 Set-Cookie 头的一部分,使用分号加空格分隔每一段,如下例所示。
Set-Cookie: name=value; expires=Mon, 22-Jan-07 07:10:24 GMT; domain=.wrox.com;path=/; secure
该示例信息表示:指定了一个叫做name 的cookie,它会在格林威治时间2007 年1 月22 日7:10:24 失效,同时所有wrox.com 的子域和域名下(由path 参数指定的)所有页面都有效的cookie。因为设置了secure 标志,这个cookie 只能通过SSL 连接才能传输。
需要注意的是:域、路径、失效时间和secure 标志都是服务器给浏览器的指示,以指定何时应该发送cookie。这些参数并不会作为发送到服务器的cookie 信息的一部分,只有名值对儿才会被发送.
了解了cookie的组成之后,我们就可以开始封装cookie的操作函数了。
3.获取cookie
getCookie()
方法根据cookie 的名字获取相应的值。它会在document.cookie
字符串中查找cookie 名加上等于号的位置。如果找到了,那么使用indexOf()
查找该位置之后的第一个分号(表示了该cookie 的结束位置)。如果没有找到分号,则表示该cookie 是字符串中的最后一个,则余下的字符串都是cookie 的值。该值使用decodeURIComponent()进行解码并最后返回。如果没有发现cookie,则返回null。
function getCookie(name){
//首先判断是否有cookie
if(document.cookie.length > 0){
//将需要获取的name进行编码
var cookieName = encodeURIComponent(name) + "=",
//在当前cookie中检索是否有要获取的name
cookieStart = document.cookie.indexOf(cookieName),
cookieValue = null;
//当前cookie中如果有要获取的name
if(cookieStart != -1){
cookieStart = cookieStart + cookieName.length;
//以name=为起始,向后寻找第一个分号;
var cookieEnd = document.cookie.indexOf(";",cookieStart);
//如果没有找到分号,则表明该name位于cookie的最后一个键值对,那么cookieEnd直接去整个cookie的长度
if (cookieEnd == -1) {
cookieEnd = document.cookie.length;
}
//如果找到分号,则进行字符串分割,即可获得cookie字符串中键为name的值cookieValue
cookieVlue = decodeURIComponent(document.cookie.substring(cookieStart,cookieEnd));
}
return cookieVlue;
}
}
4.设置cookie
setCookie()
方法在页面上设置一个cookie,接收如下几个参数:
- cookie 的名称
- cookie 的值
- 可选的cookie的有效时间(单位:毫秒)
- 可选的URL 路径
- 可选的域
- 可选的表示是否要添加secure 标志的布尔值
参数是按照它们的使用频率排列的,只有头两个是必需的。在这个方法中,名称和值都使用encodeURIComponent()
进行了URL编码,并检查其他选项。方法的其他部分就是构造cookie 字符串并将其设置到document.cookie
中。
function setCookie(name, value, expires, path, domain, secure){
/*
*name:必须,要设置的cookie名称
*value:必须,要设置的cookie的值
*expires:可选,要设置的cookie的有效时间,单位为毫秒
*path:可选,对于指定域中的那个路径,应该向服务器发送cookie
*domain:可选,要设置的cookie对于哪个域是有效的
*secure:可选,布尔值,要设置的cookie是否只有在使用SSL连接的时候才发送到服务器
*/
var cookieText = encodeURIComponent(name) + "=" + encodeURIComponent(value);
if (expires) {
//将当前时间加上设置的有效时间得到该cookie最终的失效时间
var d = new Date();
d.setDate(d.getDate() + expires)
cookieText += "; expires=" + d.toGMTString();
}
if (path) {
cookieText += "; path=" + path;
}
if (domain) {
cookieText += "; domain=" + domain;
}
if (secure) {
cookieText += "; secure";
}
document.cookie = cookieText;
}
5.删除cookie
我们知道,不在有效期内的cookie将会被浏览器自动清除,因此,想要删除cookie我们只需将该cookie的失效时间设置为过去的时间即可。设置cookie的失效时间我们可以调用上面封装好的设置cookie函数,只需将expries
参数设置为-10000即可
function delCookie(name, path, domain, secure){
setCookie(name, "", -10000, path, domain, secure )
}
6.总结
我们可以将上面封装好的三个操作cookie的方法整合起来写入单独的JS文件cookieUtil.js
,方便日后使用。
var cookieUtil = {
getCookie:function (name){
//首先判断是否有cookie
if(document.cookie.length > 0){
//将需要获取的name进行编码
var cookieName = encodeURIComponent(name) + "=",
//在当前cookie中检索是否有要获取的name
cookieStart = document.cookie.indexOf(cookieName),
cookieValue = null;
//当前cookie中如果有要获取的name
if(cookieStart != -1){
cookieStart = cookieStart + cookieName.length;
//以name=为起始,向后寻找第一个分号;
var cookieEnd = document.cookie.indexOf(";",cookieStart);
//如果没有找到分号,则表明该name位于cookie的最后一个键值对,那么cookieEnd直接去整个cookie的长度
if (cookieEnd == -1) {
cookieEnd = document.cookie.length;
}
//如果找到分号,则进行字符串分割,即可获得cookie字符串中键为name的值cookieValue
cookieVlue = decodeURIComponent(document.cookie.substring(cookieStart,cookieEnd));
}
return cookieVlue;
}
},
setCookie:function (name){
//首先判断是否有cookie
if(document.cookie.length > 0){
//将需要获取的name进行编码
var cookieName = encodeURIComponent(name) + "=",
//在当前cookie中检索是否有要获取的name
cookieStart = document.cookie.indexOf(cookieName),
cookieValue = null;
//当前cookie中如果有要获取的name
if(cookieStart != -1){
cookieStart = cookieStart + cookieName.length;
//以name=为起始,向后寻找第一个分号;
var cookieEnd = document.cookie.indexOf(";",cookieStart);
//如果没有找到分号,则表明该name位于cookie的最后一个键值对,那么cookieEnd直接去整个cookie的长度
if (cookieEnd == -1) {
cookieEnd = document.cookie.length;
}
//如果找到分号,则进行字符串分割,即可获得cookie字符串中键为name的值cookieValue
cookieVlue = decodeURIComponent(document.cookie.substring(cookieStart,cookieEnd));
}
return cookieVlue;
}
},
delCookie:function (name, path, domain, secure){
this.setCookie(name, "", -10000, path, domain, secure )
}
}
export default cookieUtil;
(完)