Cookie个数压缩存存储实践
提到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个数压缩存存储实践的更多相关文章
- 大数据技术之_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支持的压缩 ...
 - JavaScript本地存储实践(html5的localStorage和ie的userData)
		
http://www.css88.com/archives/3717 JavaScript本地存储实践(html5的localStorage和ie的userData) 发表于 2011年06月11日 ...
 - Oracle数据库部分迁至闪存存储方案
		
Oracle数据库部分迁至闪存存储方案 1.实施需求 2.确认迁移表空间信息 3.确认redo信息 4.确认undo信息 5.表空间迁移到闪存 6.redo迁移到闪存 7.undo迁移到闪存 8.备库 ...
 - Hive压缩和存储(十二)
		
压缩和存储 1. Hadoop压缩配置 1) MR支持的压缩编码 压缩格式 工具 算法 文件扩展名 是否可切分 DEFAULT 无 DEFAULT .deflate 否 Gzip gzip DEFAU ...
 - JSP中的“小饼干”Cookie,用来存储数组的方式(下方已String类型的数组为例:)
		
1.Cookie常用方法中,存储数据的方式: Cookie cookie = new Cookie("key","Value"); response.addCo ...
 - php 压缩数据存储
		
php 压缩数据存储 当接收到大量的数据时,存储到数据库和从数据库读取时,时间都比较慢,所以压缩一下入库可能会好一点. 仅供参考!!! 封装的压缩数据函数: /** * 压缩数据 * @param s ...
 - MapGIS文件如何压缩存盘
		
经过多次编辑修改的MapGIS数据,含有大量逻辑上已删除的节点或图元,数据冗余复杂, 在转换过程前应注意一定要采用压缩存盘方式处理,目的是确保编辑状态已删除的数据真正从物理存储层删除,以确保数据的精简 ...
 - C语言中结构体内存存储方式
		
C语言中结构体内存存储方式 结构体的默认存储方式采用以最大字节元素字节数对其方式进行对齐,例如一个结构体中定义有char.int类型元素,则结构体存储空间按照int类型占用字节,如果还有double类 ...
 - 临时存存储页面上的数据---js中的cookie
		
实现的效果: 当点击某个按钮的时候,实现点击A的同时,弹出B的注册div,使填写在B信息数据保存下来,点击B的确定按钮,B消失,A的图标往后移动一格,原来的位置为图标C,点击C可以弹出来一个链接的页面 ...
 
随机推荐
- leetcode 之Reorder List(25)
			
找到中间结点,将后半部分反转接入即可. ListNode *reoderList(ListNode* head) { if (head == nullptr || head->next == n ...
 - Storm实战常见的问题
			
该文档为实实在在的原创文档,转载请注明: http://blog.sina.com.cn/s/blog_8c243ea30101k0k1.html 类型 详细 备注 该文档是群里几个朋友在storm实 ...
 - 利用Node 搭配uglify-js压缩js文件,批量下载图片到本地
			
Node的便民技巧-- 压缩代码 下载图片 压缩代码 相信很多前端的同学都会在上线前压缩JS代码,现在的Gulp Webpack Grunt......都能轻松实现.但问题来了,这些都不会,难道就要面 ...
 - es6数组必看太实用了
			
随着前后分离,前端人员也要写大量的逻辑代码,es5很多地方尤其是数据工具大拿数组,很多时候都是捉襟见肘. 继而,es6为我们扩展了很多good的工具和方法,让我们一起学习es6吧. 1原型方法from ...
 - 创建jenkins任务
			
前提条件 整个持续集成中用的相关的应用: gitlab (代码管理) maven(项目管理) 这些应用我们暂时全部放在了一个服务器上. 安装maven: CentOS 6.3 安装Maven3(就一步 ...
 - Linux的重定向与管道
			
(1).输出重定向 定义:将命令的标准输出结果保存到指定的文件中,而不是直接显示在显示器上. 输出重定向使用>和>>操作符. 语法:cmd > filename,表示将标准输出 ...
 - XML--读写操作
			
XML文档的相关操作 1.配置文件:在实际项目开发中,XML作为配置文件是不可取代的(框架中的部分功能可以以注解形式来取代) (1) 不同技术,XML配置文件的作用也不一样. (2) 比如当前和这个阶 ...
 - BZOJ 3790 神奇项链(manacher+DP+树状数组)
			
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3790 [题目大意] 问最少用几个回文串可以构成给出串,重叠部分可以合并 [题解] 我们 ...
 - 【数论】【原根】【动态规划】【bitset】2017四川省赛 K.2017 Revenge
			
题意: 给你n(不超过200w)个数,和一个数r,问你有多少种方案,使得你取出某个子集,能够让它们的乘积 mod 2017等于r. 2017有5这个原根,可以使用离散对数(指标)的思想把乘法转化成加法 ...
 - 【计算几何】【圆反演】hdu6097 Mindis
			
给你一个中心在原点的圆,再给你俩在圆内且到原点距离相等的点P,Q,让你在圆上求一点D,最小化DP+DQ. http://blog.csdn.net/qq_34845082/article/detail ...