前段时间在一个项目中涉及到cookie的存取,于是打算封装一个 cookie 的CRUD 。按理来说,这本身是一个很简单的问题,不注意的话简单的问题也有大坑。
/**
* Set or get cookie ;parse to object
*
*@date 2015-04-11
*
*@author 飘摇的枫叶
*
*
*
*/
'use strict';
(function (window) {
// class2type refer to zepto.js $.type(obj) ## https://github.com/madrobby/zepto
var class2type = {},
toString = class2type.toString;
"Boolean Number String Function Array Date RegExp Object Error".split(" ").forEach(function(name) {
class2type["[object " + name + "]"] = name.toLowerCase();
}); var _qcookie = {
cookies: document.cookie,
get: function(name) {
return this.all()[name];
},
/*
*Set cookie
*
*@param {string} cookieName
*@param {string} cookieValue
* or
*@param {object} cookieObject{key:value}
*
*@param {object} options{path:'/demo';domain:'/';expire:new Date();secure:0|1}
*/
set: function(name, value, options) {
var opt = options || {};
if (!name) return;
if (type(name) === 'string' && value) {
this.write(name, value, opt);
} else if (type(name) === 'object') {
opt = value || {};
for (var k in name) {
this.write(k, name[k], opt);
}
}
// if (type(name) === 'string' && value) {
// str = encode(name) + '=' + encode(value) + '; ';
// } else if (type(name) === 'object') {
// opt = value || {};
// for (var k in name) {
// str += encode(k) + '=' + encode(name[k]) + '; ';
// }
// }
// if (opt.path) str += 'path=' + opt.path;
// if (opt.domain) str += 'domain=' + opt.domain;
// if (opt.expires) str += 'expires=' + opt.expires.toUTCString();
// if (opt.secure) str += 'secure';
// document.cookie = str;
},
all: function() {
return this.parse(this.cookies);
},
delete: function(name) {
var expires = new Date();
expires.setDate(expires.getDate() - 1);
document.cookie = name + "=" + this.get(name) + '; expires=' + expires.toUTCString();
},
write: function(name, value, opt) {
var str = encode(name) + '=' + encode(value);
if (opt.path) str += '; path=' + opt.path;
if (opt.domain) str += '; domain=' + opt.domain;
if (opt.expires) str += '; expires=' + opt.expires.toUTCString();
if (opt.secure) str += '; secure';
document.cookie = str;
},
parse: function(cookieStr) {
var obj = {};
var arrs = cookieStr.split(/ *; */); // Similar with the split(';') + trim()
var kv = [];
if (arrs[0] == '') {
return obj;
}
for (var i = 0; i < arrs.length; i++) {
kv = arrs[i].split('=');
obj[decode(kv[0])] = decode(kv[1]);
}
return obj;
}
} function encode(str) {
return encodeURIComponent(str);
} function decode(str) {
return decodeURIComponent(str);
} function type(obj) {
return obj == null ? String(obj) :
class2type[toString.call(obj)] || "object"
}
window.qcookie = _qcookie;
})(window)
仔细一看你会发现这里面会有个很严重的问题,当不同域或者不同path的同名cookie 在读和删除的时候都会有问题 ,由于 cookie 的 domain , path 等属性是只写的,你读取到的两个cookie 结构可能是完全一样的,根本无法区分,类似这样,
由于我采用的是将cookie parse 一个对象, 当你只传一个name 的时候,第二个 'aaa' 必然会将第一个 'aaa' 的值给覆盖掉,,这个问题一时间还真没想到什么好的办法解决,又或者设计的时候压根就没有考虑过这个问题,因为实际项目中可能并不会出现这么看上去很傻X的使用场景,然而多了解一点总是极好的。
而删除的话,cookie 本身并没有提供删除的api , cookie 的删除完全是已写cookie的方式,加上一个失效时间,所以删除时指定path cookie 通过设置domain , path 还是可以做到的。