zoukankan      html  css  js  c++  java
  • 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里面 ,里面涉及到很多问题,如域、路径、有效期等,下来直接看一下源码先:

      1 /**
      2 * cookie操作模块
      3 * @name cookiex
      4 * @function
      5 * @param {String} key
      6 * @param {String} [value]
      7 * @param {{expires:Number|'forever', domain:String, path:String , inCommon: boolean , secure : boolean}} [options]
      8 * @reutrns {String}
      9 * @example
     10 * cookiex(key); //读取cookie
     11 * cookiex(key, null); //删除cookie
     12 * cookiex(key, value, {"expires":forever,"domain":"mydomain.com","path":"/" , inCommon : false }); //设置cookie
     13 */
     14 function cookiex(key,value,options){
     15 
     16         var options = options || {},
     17             ret,
     18             result, 
     19             getRet = function(tkey){
     20                 var tret = '';
     21                 if(result = new RegExp('(?:^|; )' + encodeURIComponent(tkey) + '=([^;]*)').exec(document.cookie)) {
     22                     try {
     23                         tret = decodeURIComponent(result[1]);
     24                     } catch(e) {
     25                         tret = result[1];
     26                     }
     27                 }
     28                 return tret;
     29             };
     30 
     31 
     32         // key and value given, set cookie...
     33         if (arguments.length > 1 && (value === null || typeof value !== "object")) {
     34                 
     35             if (value === null) {
     36                 
     37                 
     38                 //删除forever里面的东西,只改key和expires,在最后才写cookie
     39                 var forever = getRet("my_common_forever"),
     40                     inCommon = false,
     41                     oldKey = key,
     42                     oldDomain = options.domain ,
     43                     oldPath = options.path;
     44 
     45 
     46                 if(forever != ''){
     47                     var foreverList =  forever.split('&');
     48                     for(var i = 0; i < foreverList.length; i++){
     49                         if(foreverList[i].split('=')[0] == key){
     50                             foreverList.splice(i,1);
     51                             key =  "my_common_forever";
     52                             value = foreverList.join("&");
     53                             options.expires = new Date(0xfffffffffff);
     54                             options.domain = "mydomain.com";
     55                             options.path = "/";
     56                             inCommon = true;
     57                             break;
     58                         }
     59                     }            
     60                 }
     61 
     62                 //删除session里面的东西,只改key和expires,在最后才写cookie
     63                 if(!inCommon){
     64                     var session = getRet("my_common_session");
     65                     if(session != ''){
     66                         var sessionList =  session.split('&');
     67                         for(var i = 0; i < sessionList.length; i++){
     68                             if(sessionList[i].split('=')[0] == key){
     69                                 sessionList.splice(i,1);
     70                                 key =  "my_common_session";
     71                                 value = sessionList.join("&");
     72                                 options.expires = null;
     73                                 options.domain = "mydomain.com";
     74                                 options.path = "/";
     75                                 inCommon = true;
     76                                 break;
     77                             }
     78                         }            
     79                     }
     80                 }
     81 
     82                 //如果不在公用cookie里面就直接在最后删除原生cookie就行了,如果在公用cookie里面就改变
     83                 if(!inCommon){
     84                     value = '';
     85                     options.expires = new Date(0);
     86                 }else{
     87                     //删除原生cookie,带直接写cookie操作
     88                     document.cookie = [
     89                         encodeURIComponent(oldKey), 
     90                         '=', 
     91                         "" ,
     92                         '; expires=' + (new Date(0)).toGMTString(), 
     93                         oldPath ? '; path=' + oldPath : '; path=/',
     94                         oldDomain ? '; domain=' + oldDomain : '; domain=mydomain.com',
     95                         options.secure ? '; secure' : ''
     96                     ].join('');
     97                 }
     98             }else{
     99                 //写cookie
    100                 if (typeof options.expires === 'number') {
    101                     //计时cookie,默认以秒计
    102                     var minutes = options.expires, 
    103                         t = options.expires = new Date();
    104                     t.setDate(t.getSeconds() + minutes);
    105                 } else if(typeof options.expires === 'string' && options.expires != 'forever') {
    106                     //计时cookie ,根据开发者输入的尾缀定单位
    107                     var t = parseInt(options.expires),
    108                         suffix = options.expires[options.expires.length -1],
    109                         now = new Date();;
    110                     if(suffix=="s"){
    111                         now.setSeconds(now.getSeconds() + t);
    112                         options.expires = now;
    113                     } else if(suffix=="m") {
    114                         now.setMinutes(now.getMinutes() + t);
    115                         options.expires = now;
    116                     } else if(suffix=="h") {
    117                         now.setHours(now.getHours() + t);
    118                         options.expires = now;
    119                     } else if(suffix=="d") {
    120                         now.setDate(now.getDate() + t)
    121                         options.expires = now;
    122                     } else if(suffix=="M") {
    123                         now.setMonth(now.getMonth() + t);
    124                         options.expires = now;
    125                     }
    126                 } else if(options.expires == 'forever') {
    127                     //永久cookie
    128                     options.expires = new Date(0xfffffffffff);
    129                     if(options.inCommon){
    130                         //如果使用公用cookie,强制使用domain : .mydomain.com这个和 path : /
    131                         options.domain = "mydomain.com";
    132                         options.path = "/";
    133                         var forever = cookiex("my_common_forever");        
    134                         if(forever!=''){
    135 
    136                             var retList =  forever.split('&'),
    137                                 inForever = false;
    138                             
    139                             for(var i = 0; i < retList.length; i++){
    140                                 if(retList[i].split('=')[0] == key){
    141                                     retList[i] = key + '=' + encodeURIComponent(String(value));
    142                                     inForever = true;
    143                                     break;
    144                                 }
    145                             }
    146 
    147                             if(!inForever){
    148                                 value = forever + "&" + key + '=' + encodeURIComponent(String(value));    
    149                             }else{
    150                                 value = retList.join('&');
    151                             }
    152 
    153                         }else{                    
    154                             value = key + '=' + encodeURIComponent(String(value));
    155                         }        
    156                         key = "my_common_forever";
    157                     }
    158                 } else if( typeof options.expires === "object" && (a instanceof Date)){
    159                     //用户自己传入Date对象
    160                 } else {
    161                     //浏览器进程cookie
    162                     options.expires = null;
    163                     if(options.inCommon){
    164                         //如果使用公用cookie,强制使用domain : .mydomain.com这个和 path : /
    165                         options.domain = "mydomain.com";
    166                         options.path = "/";
    167                         var session = cookiex("my_common_session");    
    168                         if(session!=''){
    169 
    170                             var retList =  session.split('&'),
    171                                 inSession = false;
    172                             
    173                             for(var i = 0; i < retList.length; i++){
    174                                 if(retList[i].split('=')[0] == key){
    175                                     retList[i] = key + '=' + encodeURIComponent(String(value));
    176                                     inSession = true;
    177                                     break;
    178                                 }
    179                             }
    180 
    181 
    182                             if(!inSession){
    183                                 value = session + "&" + key + '=' + encodeURIComponent(String(value));
    184                             }else{
    185                                 value = retList.join('&');
    186                             }
    187                         }else{                    
    188                             value = key + '=' + encodeURIComponent(String(value));
    189                         }            
    190                         key = "my_common_session";
    191                     }
    192                 }
    193 
    194             }
    195 
    196 
    197             //执行操作
    198             return (document.cookie = [
    199                 encodeURIComponent(key), '=',
    200                 options.raw ? String(value) : encodeURIComponent(String(value)),
    201                 options.expires ? '; expires=' + options.expires.toGMTString() : '', // use expires attribute, max-age is not supported by IE
    202                 options.path ? '; path=' + options.path : '; path=/',
    203                 options.domain ? '; domain=' + options.domain : '; domain=mydomain.com',
    204                 options.secure ? '; secure' : ''
    205             ].join('')); 
    206         }
    207 
    208 
    209         // key and possibly options given, get cookie...
    210         options = value || {};
    211         ret = getRet(key);    
    212         
    213         //查找永久公用cookie
    214         if(ret == '' && key != 'my_common_forever') {
    215             ret = getRet("my_common_forever");
    216             if(ret != ''){
    217                 var retList =  ret.split('&');
    218                 for(var i = 0; i < retList.length; i++){
    219                     if(retList[i].split('=')[0] == key){
    220                         ret = decodeURIComponent(retList[i].split('=')[1]);
    221                         return ret ;
    222                     }
    223                 }            
    224             }
    225             ret = '';
    226         }
    227 
    228         //查找浏览器进程公用cookie
    229         if(ret == '' && key != 'my_common_session') {
    230             ret = getRet("my_common_session");
    231             if(ret != ''){
    232                 var retList =  ret.split('&');
    233                 for(var i = 0; i < retList.length; i++){
    234                     if(retList[i].split('=')[0] == key){
    235                         ret = decodeURIComponent(retList[i].split('=')[1]);
    236                         return ret ;
    237                     }
    238                 }            
    239             }
    240             ret = '';
    241         }
    242 
    243         return ret;
    244 }

    一看,操作个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进行相应的读写操作。

    本文为原创文章,转载请注明出处:http://www.cnblogs.com/zernmal/
  • 相关阅读:
    面向对象设计与实用的思考(主动对象与被动对象)
    改进弧长法 判断点是否在多边形内 c#代码
    PaintCode begin
    kiwivm putty lnmp
    初心已变,我也不是当时的我
    spfa
    tree dp
    开心就好之修行ing
    MIME 参考手册
    TypeScript学习和参考手册
  • 原文地址:https://www.cnblogs.com/zernmal/p/3745709.html
Copyright © 2011-2022 走看看