提到cookie,大家都不会陌生的,几乎涉及到交互或统计的WEB系统都会使用到cookie,关于cookie的基础知识网上也有很多,这里推荐两篇文章:

  聂微东的: http://www.cnblogs.com/Darren_code/archive/2011/11/24/Cookie.html#2933759

  张子秋的:http://www.cnblogs.com/zhangziqiu/archive/2009/08/06/cookies-javascript-aspnet.html

cookie,很实用,但是在各大浏览器里面限制比较多,下面是各浏览器对cookie大小和个数的限制:

  IE6.0 IE7.0/IE8.0 Opera FF Safari Chrome
cookie个数  每个域为20个 每个域为50个 每个域为30个 每个域为50个 没有个数限制   每个域为53个
cookie大小 4095个字节 4095个字节 4096个字节 4097个字节 4097个字节 4097个字节

看到这张表,突然感到好忧伤,因为我们的项目还要一直兼容IE6,IE在Cookie方面只能保留20个,较旧的会被清掉。 表中Opera是30个,但是新版的Opera已经开始使用webkit内核了,应该也是50个以上的了。

今天我们来讨论的就是解决cookie个数太多的问题,我的做法就是将多个cookie压缩在一个cookie里面 ,里面涉及到很多问题,如域、路径、有效期等,下来直接看一下源码先:

 /**
* cookie操作模块
* @name cookiex
* @function
* @param {String} key
* @param {String} [value]
* @param {{expires:Number|'forever', domain:String, path:String , inCommon: boolean , secure : boolean}} [options]
* @reutrns {String}
* @example
* cookiex(key); //读取cookie
* cookiex(key, null); //删除cookie
* cookiex(key, value, {"expires":forever,"domain":"mydomain.com","path":"/" , inCommon : false }); //设置cookie
*/
function cookiex(key,value,options){ var options = options || {},
ret,
result,
getRet = function(tkey){
var tret = '';
if(result = new RegExp('(?:^|; )' + encodeURIComponent(tkey) + '=([^;]*)').exec(document.cookie)) {
try {
tret = decodeURIComponent(result[1]);
} catch(e) {
tret = result[1];
}
}
return tret;
}; // key and value given, set cookie...
if (arguments.length > 1 && (value === null || typeof value !== "object")) { if (value === null) { //删除forever里面的东西,只改key和expires,在最后才写cookie
var forever = getRet("my_common_forever"),
inCommon = false,
oldKey = key,
oldDomain = options.domain ,
oldPath = options.path; if(forever != ''){
var foreverList = forever.split('&');
for(var i = 0; i < foreverList.length; i++){
if(foreverList[i].split('=')[0] == key){
foreverList.splice(i,1);
key = "my_common_forever";
value = foreverList.join("&");
options.expires = new Date(0xfffffffffff);
options.domain = "mydomain.com";
options.path = "/";
inCommon = true;
break;
}
}
} //删除session里面的东西,只改key和expires,在最后才写cookie
if(!inCommon){
var session = getRet("my_common_session");
if(session != ''){
var sessionList = session.split('&');
for(var i = 0; i < sessionList.length; i++){
if(sessionList[i].split('=')[0] == key){
sessionList.splice(i,1);
key = "my_common_session";
value = sessionList.join("&");
options.expires = null;
options.domain = "mydomain.com";
options.path = "/";
inCommon = true;
break;
}
}
}
} //如果不在公用cookie里面就直接在最后删除原生cookie就行了,如果在公用cookie里面就改变
if(!inCommon){
value = '';
options.expires = new Date(0);
}else{
//删除原生cookie,带直接写cookie操作
document.cookie = [
encodeURIComponent(oldKey),
'=',
"" ,
'; expires=' + (new Date(0)).toGMTString(),
oldPath ? '; path=' + oldPath : '; path=/',
oldDomain ? '; domain=' + oldDomain : '; domain=mydomain.com',
options.secure ? '; secure' : ''
].join('');
}
}else{
//写cookie
if (typeof options.expires === 'number') {
//计时cookie,默认以秒计
var minutes = options.expires,
t = options.expires = new Date();
t.setDate(t.getSeconds() + minutes);
} else if(typeof options.expires === 'string' && options.expires != 'forever') {
//计时cookie ,根据开发者输入的尾缀定单位
var t = parseInt(options.expires),
suffix = options.expires[options.expires.length -1],
now = new Date();;
if(suffix=="s"){
now.setSeconds(now.getSeconds() + t);
options.expires = now;
} else if(suffix=="m") {
now.setMinutes(now.getMinutes() + t);
options.expires = now;
} else if(suffix=="h") {
now.setHours(now.getHours() + t);
options.expires = now;
} else if(suffix=="d") {
now.setDate(now.getDate() + t)
options.expires = now;
} else if(suffix=="M") {
now.setMonth(now.getMonth() + t);
options.expires = now;
}
} else if(options.expires == 'forever') {
//永久cookie
options.expires = new Date(0xfffffffffff);
if(options.inCommon){
//如果使用公用cookie,强制使用domain : .mydomain.com这个和 path : /
options.domain = "mydomain.com";
options.path = "/";
var forever = cookiex("my_common_forever");
if(forever!=''){ var retList = forever.split('&'),
inForever = false; for(var i = 0; i < retList.length; i++){
if(retList[i].split('=')[0] == key){
retList[i] = key + '=' + encodeURIComponent(String(value));
inForever = true;
break;
}
} if(!inForever){
value = forever + "&" + key + '=' + encodeURIComponent(String(value));
}else{
value = retList.join('&');
} }else{
value = key + '=' + encodeURIComponent(String(value));
}
key = "my_common_forever";
}
} else if( typeof options.expires === "object" && (a instanceof Date)){
//用户自己传入Date对象
} else {
//浏览器进程cookie
options.expires = null;
if(options.inCommon){
//如果使用公用cookie,强制使用domain : .mydomain.com这个和 path : /
options.domain = "mydomain.com";
options.path = "/";
var session = cookiex("my_common_session");
if(session!=''){ var retList = session.split('&'),
inSession = false; for(var i = 0; i < retList.length; i++){
if(retList[i].split('=')[0] == key){
retList[i] = key + '=' + encodeURIComponent(String(value));
inSession = true;
break;
}
} if(!inSession){
value = session + "&" + key + '=' + encodeURIComponent(String(value));
}else{
value = retList.join('&');
}
}else{
value = key + '=' + encodeURIComponent(String(value));
}
key = "my_common_session";
}
} } //执行操作
return (document.cookie = [
encodeURIComponent(key), '=',
options.raw ? String(value) : encodeURIComponent(String(value)),
options.expires ? '; expires=' + options.expires.toGMTString() : '', // use expires attribute, max-age is not supported by IE
options.path ? '; path=' + options.path : '; path=/',
options.domain ? '; domain=' + options.domain : '; domain=mydomain.com',
options.secure ? '; secure' : ''
].join(''));
} // key and possibly options given, get cookie...
options = value || {};
ret = getRet(key); //查找永久公用cookie
if(ret == '' && key != 'my_common_forever') {
ret = getRet("my_common_forever");
if(ret != ''){
var retList = ret.split('&');
for(var i = 0; i < retList.length; i++){
if(retList[i].split('=')[0] == key){
ret = decodeURIComponent(retList[i].split('=')[1]);
return ret ;
}
}
}
ret = '';
} //查找浏览器进程公用cookie
if(ret == '' && key != 'my_common_session') {
ret = getRet("my_common_session");
if(ret != ''){
var retList = ret.split('&');
for(var i = 0; i < retList.length; i++){
if(retList[i].split('=')[0] == key){
ret = decodeURIComponent(retList[i].split('=')[1]);
return ret ;
}
}
}
ret = '';
} return ret;
}

一看,操作个cookie两百多行代码,有点小多,这里我来一个个解释一下,为什么会有这么多代码。

公用cookie :

这里我使用了两个公用的cookie,my_common_session(跟随浏览器进程)和my_common_forever(永久cookie),里面的多个cookie使用 & 符号连接起来,然后用 encodeURIComponent 进行编码。

我把公用cookie的域写死在一个域和路径里面了,这样可以保证读写公用cookie的时候不会因为输入的域不同导致调用不到,一般都是网站的顶级域名,可以按照自己的需求修改。

cookie添加或修改:

在cookie添加或修改的时候判断inCommon 是否为true,如果是的话,就往对应的公用cookie里面添加,否则便以传统的方式添加或修改cookie。

在添加进公用cookie的时候,需要注意的是公用cookie里面是不是已经存在有了,如果不存在就进行添加,如果之前有过的了,便进行值替换,具体是在代码的第 126~192行间。

添加非公用cookie时跟普通的cookie操作差不多,这里也提供了很多关于时间的参数。

/* 调用案例 */
cookiex("a","value-of-cookie-a");
cookiex("a"); //"abcc" cookiex("b","value-of-cookie-b",{inCommon:true});
cookiex("b"); // "bbbb" cookiex("c","value-of-cookie-c",{expires:"forever",inCommon:true});
cookiex("c"); //"value-of-cookie-c" cookiex("d","value-of-cookie-d",{expires:"3h"});
cookiex("d"); //"value-of-cookie-d"

cookie删除:

关于cookie删除操作,这里有两步操作,一步是判断公用cookie里面有没有对应的key,有的话便删除,第二步是删除非公用cookie里面对应的cookie。

/* 调用案例 */

cookiex("d",null) 

可能存在问题及解决:

一个项目里面有不同人对cookie进行操作的时候,可能会同一个key的cookie即存在公用的cookie里面,又存在非公用的cookie里面。在上面的方法里是优先读取了非公用的cookie的,但是这样重复存在难免会造成一些混淆,所以解决方案是团队内部沟通好,约定好一些cookie怎么用。

与服务端结合:

cookie被这样压缩后,服务端就不能直接通过传统的方式去读取这些cookie了,所以我们可以在后台使有类似的方式封装一个方法对cookie进行相应的读写操作。

Cookie个数压缩存存储实践的更多相关文章

  1. 大数据技术之_08_Hive学习_04_压缩和存储(Hive高级)+ 企业级调优(Hive优化)

    第8章 压缩和存储(Hive高级)8.1 Hadoop源码编译支持Snappy压缩8.1.1 资源准备8.1.2 jar包安装8.1.3 编译源码8.2 Hadoop压缩配置8.2.1 MR支持的压缩 ...

  2. JavaScript本地存储实践(html5的localStorage和ie的userData)

    http://www.css88.com/archives/3717 JavaScript本地存储实践(html5的localStorage和ie的userData) 发表于 2011年06月11日  ...

  3. Oracle数据库部分迁至闪存存储方案

    Oracle数据库部分迁至闪存存储方案 1.实施需求 2.确认迁移表空间信息 3.确认redo信息 4.确认undo信息 5.表空间迁移到闪存 6.redo迁移到闪存 7.undo迁移到闪存 8.备库 ...

  4. Hive压缩和存储(十二)

    压缩和存储 1. Hadoop压缩配置 1) MR支持的压缩编码 压缩格式 工具 算法 文件扩展名 是否可切分 DEFAULT 无 DEFAULT .deflate 否 Gzip gzip DEFAU ...

  5. JSP中的“小饼干”Cookie,用来存储数组的方式(下方已String类型的数组为例:)

    1.Cookie常用方法中,存储数据的方式: Cookie cookie = new Cookie("key","Value"); response.addCo ...

  6. php 压缩数据存储

    php 压缩数据存储 当接收到大量的数据时,存储到数据库和从数据库读取时,时间都比较慢,所以压缩一下入库可能会好一点. 仅供参考!!! 封装的压缩数据函数: /** * 压缩数据 * @param s ...

  7. MapGIS文件如何压缩存盘

    经过多次编辑修改的MapGIS数据,含有大量逻辑上已删除的节点或图元,数据冗余复杂, 在转换过程前应注意一定要采用压缩存盘方式处理,目的是确保编辑状态已删除的数据真正从物理存储层删除,以确保数据的精简 ...

  8. C语言中结构体内存存储方式

    C语言中结构体内存存储方式 结构体的默认存储方式采用以最大字节元素字节数对其方式进行对齐,例如一个结构体中定义有char.int类型元素,则结构体存储空间按照int类型占用字节,如果还有double类 ...

  9. 临时存存储页面上的数据---js中的cookie

    实现的效果: 当点击某个按钮的时候,实现点击A的同时,弹出B的注册div,使填写在B信息数据保存下来,点击B的确定按钮,B消失,A的图标往后移动一格,原来的位置为图标C,点击C可以弹出来一个链接的页面 ...

随机推荐

  1. python初学-元组、集合

    元组: 元组基本和列表一样,区别是 元组的值一旦创建 就不能改变了 tup1=(1,2,3,4,5) print(tup1[2]) ---------------------------------- ...

  2. 步骤一:下载jdk并安装和配置java环境变量

    1.下载JDk地址: http://download.eclipse.org/oomph/jre/?vm=1_1_7_0_64_0 2.进入下载页面(下载的是jdk7),点击:Oracle JDK1. ...

  3. java中的构造方法与其作用

    什么是构造方法呢? 方法名和类名相同 没有返回值类型,连void都不能写 没有具体的返回值 构造方法分为无参构造方法与有参构造方法. 先来看一下最简单的无参构造方法: Student.java pac ...

  4. JAX-RS Resteasy

    JAX-RS (JSR-311) 是为 Java EE 环境下的 RESTful 服务能力提供的一种规范.它能提供对传统的基于 SOAP 的 Web 服务的一种可行替代. https://www.ib ...

  5. Mysql 中的Text字段的范围

    mysql中text 最大长度为65,535(2的16次方–1)字符的TEXT列.如果你觉得text长度不够,可以选择 MEDIUMTEXT最大长度为16,777,215. LONGTEXT最大长度为 ...

  6. 计划任务at cron

    计划任务作用:做一些周期性的任务,主要用于定时备份数据,同步时间,定时删除日志 所有计划任务执行的输出都会以邮件的方式发送给指定用户,除非重定向 (1)at:一次性调度执行 1)安装 yum inst ...

  7. 345. Reverse Vowels of a String【Easy】【双指针-反转字符串中的元音字符】

    Write a function that takes a string as input and reverse only the vowels of a string. Example 1: In ...

  8. ZUFEOJ 2147 07染色带谜题

    2147: 07染色带谜题 时间限制: 1 Sec  内存限制: 128 MB提交: 170  解决: 21[提交][状态][讨论版][Edit] [TestData] 题目描述 现在给你一个长为N的 ...

  9. JSP2 自定义标签

    实现步骤 实现自定义标签的处理类继承javax.servlet.jsp.tagext.SimpleTagSupport,并重写doTag方法 建立标签库配置文件 在jsp中使用自定义标签 一个简单的标 ...

  10. 《深入浅出Nodejs》笔记——模块机制(2)

    前言 书上还有很大一部分讲了C/C++模块的编译过程.核心模块编写和C/C++扩展模块的内容,不过我对C++一窍不通因此没有仔细看,如果以后需要再自习看吧. 包与NPM 第三方模块中,模块和模块之间是 ...