提到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. 安装lszrz,用于上传文件

    wget http://down1.chinaunix.net/distfiles/lrzsz-0.12.20.tar.gztar zxvf lrzsz-0.12.20.tar.gzcd lrzsz- ...

  2. CF1064 E - Dwarves, Hats and Extrasensory Abilities

    题意 交互题, 本来应该是在平面上进行的. 实际上换成一条直线就可以, 其实换成在平面上更复杂一些. Solution 假设\(l\)点是黑点, \(r\)处是白点, 那么就把下一个点的位置放置在\( ...

  3. Django web框架之模板

    1 模板: 什么是模板? html+模板语法 模版包括在使用时会被值替换掉的 变量,和控制模版逻辑的 标签. 2 模板语法: 1 变量:{{}} 深度查询: 通过句点符号 . 过滤器 filter { ...

  4. Linux:hping高级主机扫描

    https://www.aliyun.com/jiaocheng/167107.html https://blog.csdn.net/weixin_39762926/article/details/7 ...

  5. 02 java 基础:java 文件名与类名关系 CLASSPATH

    java 类修饰符:通常情况下使用 public 修饰,此时,java 强制要求 .java 文件名需与该 public 修饰类名一致,否则无法编译通过.如若没有加修饰符,文件名与类名可无任何关联. ...

  6. 配合bootstrap实现的table 嵌套table

    不要忘了引入bootstrap.css库 html部分 <div class="container"> <div class="row"> ...

  7. LoadRunner中常用函数参考手册

    基础篇1:LoadRunner中常用函数参考手册 常用函数列表 web_url web_submmit_form VS web_submmit_data VS web_custom_request w ...

  8. CentOS7安装和配置vsftpd

    (1)vsftpd基本介绍 作用:实现文件共享 1)vsftpd两种模式 主动模式 所谓主动模式,指的是FTP服务器"主动"去连接客户端的数据端口来传输数据,其过程具体来说就是:客 ...

  9. Linux让程序后台运行命令之screen与nohup

    一.nohup nohup时间长了会断掉  所以建议使用screen nohup 命令 & 如果运行成功刚默认会将标准输出重定向到当前目录的nohup.out文件中,查看此文件,可以了解运行的 ...

  10. 用Logger来解释拦截

    HZ 动态代理学了 不知道在工作中杂用哦 HE 现在一般不会直接用吧,一般都是用aspectJ这种完整aop的实现 STST 拦截方法调用 HZ 我见过把所有accessor方法放到切面的 还有tra ...