20170618-数据存储-cookie


Cookie

HTTP Cookie, 通常直接叫做cookie,最初是在客户端用于存储会话信息的。该标准要求服务器对任意HTTP请求发送Set-Cookie HTTP头作为响应的一部分,其中包含会话信息。这个HTTP响应设置一个以name为名称、以value为值的cookie,名称和值在传送时都必须是URI编码的。浏览器会存储这样的会话信息,并在这之后,通过为每个请求添加Cookie HTTP头将信息发送回服务器,发送回服务器的额外信息可以用于唯一验证客户端来自于发送的哪个请求。

Cookie的限制

数量限制

  • IE6及更低的版本每个域名限制为20个cookie,IE7及以后的版本每个域名限制为50个cookie。

  • Firefox每个域名cookie限制为50个。

  • Opera每个域名cookie限制为30个。

  • Safari和Chrome对每个域的cookie的数量限制没有硬性规定

大小限制

大多数浏览器对每个cookie有大约4096B的长度限制(大约4K)

cookie的构成

cookie由浏览器保存的以下几块信息构成

  • 名称

  • 域:cookie对哪个域是有效的,所有向该域发送的请求中都会包含这个cookie信息,默认值为设置cookie的那个域

  • 路径:指定域中的哪个路径,应该向服务器发送cookie

  • 失效时间: cookie何时应该被删除的时间戳

  • 安全标志: 指定后,cookie只有在使用SSL连接时,才会发送到服务器

尤其要注意,域、路径、失效时间、安全标志都是服务器给浏览器的标识,这些参数并不会作为发送到服务器的cookie信息的一部分,只有键值对才会被发送。

JavaScript对cookie的操作

使用document.cookie可以获取当前页面可用的所有的cookie组成的字符串,该字符串是有分号隔开的键值对构成(由分号隔开的一个键值对就是一个cookie),例如:name1=value1;name2=value2;name3=value3。所有名字和值都是经过URL编码,所以必须使用decodeURIComponent()来解码。

var CookieUtil = {
    get: function(name){
        var cookieName = encodeURIComponent(name) + '=',
            cookieStart = document.cookie.indexOf(cookieName),
            cookieValue = null;
        if(cookieStart > -1){
            cookieEnd = document.cookie.indexOf(';', cookieStart);
            if(cookieEnd == -1){
                cookieEnd = document.cookie.length;
            }
            cookieValue = decodeURIComponent(document.cookie.substring(cookieStart+cookieName.length, cookieEnd));
        }
        return cookieValue;
    },
    
    set: function(name, value, expires, path, domain, secure){
        // 设置的cookie的名称已存在,将会覆盖原有的cookie
        var cookieText = encodeURIComponent(name) + '=' + encodeURIComponent(value);
        if(expires instanceof Date){
            cookieText += "; expires=" + expires.toGMTSting();
        }
        if(path){
            cookieText += "; path=" + path;
        }
        if(domain){
            cookieText += "; domain=" + domain;
        }
        if(secure){
            cookieText += "; secure=" + secure;
        }
        document.cookie = cookieText;
    },
    
    unset: function(name, path, domain, secure){
        this.set(name, "", new Date(), path, domain, secure);
    }
}

子cookie

为了绕开浏览器的单域名下的cookie数限制,可以在每个cookie中存放多个更小的字段(子cookie)。子cookie最常见的格式如下:

name=name1=value1&name2=value2&name3=value3

子cookie一般也以查询字符串的格式进行格式化。然后这些值可以使用单个cookie进行存储和访问,而非对每个键值对使用不同的cookie存储。最后网站或web应用程序可以无需达到单域名cookie上限也可以存储更加结构化的数据。为了更好地操作子cookie,必须建立一系列新方法。子cookie的解析和序列化会因子cookie的期望用途而略有不同并更加复杂些。

var SubCookieUtil = {
    get: function(name, subName){
        var subCookies = this.getAll(name)
        if(subCookies){
            return subCookies(subName);
        } else {
            return null;
        }
    },
    
    getAll: function(name){
        var cookieName = encodeURIComponent(name) + "=",
            cookieStart = document.cookie.indexOf(cookieName),
            cookieValue = null,
            cookieEnd,
            subCookie,
            i,
            parts,
            result = {};
        
        if(cookeStart > -1){
            cookieEnd = document.cookie.indexOf(";", cookieStart);
            if(cookieEnd == -1){
                cookieEnd = document.cookie.length;
            }
            cookieValue = document.cookie.substring(cookieStart+cookieName.length, cookieEnd);
            if(cookieValue.length>0){
                subCookies = cookieValue.split("&");
                
                for(i=0, len=subCookie.length; i<len;i++){
                    parts = subCookies[i].split("=");
                    result[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]);
                }
                return result;
            }
        }
        return null;
    },
    
    set: function(name, subName, value, expires, path, domain, secure){
        var subcookies = this.getAll(name)||{};
        subcookies[subName] = value;
        this.setAll(name, subCookie, expires, path, domain, secure);
    },
    
    setAll: function(name, subcookies, expires, path, domain, secure){
        var cookieText = encodeURIComponent(name) + "=",
            subcookieParts = new Array(),
            subName;
        
        for(subName in subcookies){
            if(subName.length >0 && subcookies.hasOwnProperty(subName)){
                subcookieParts.push(encodeURIComponent(subName) + "=" +
                    encodeURIComponent(subcookies[subName]);
            }
        }
        
        if(cookieParts.length >0){
            cookieText += subcookieParts.join("&");
            if(expires instanceof Date){
                cookieText += "; expires=" + expires.toGMTSting();
            }
            if(path){
                cookieText += "; path=" + path;
            }
            if(domain){
                cookieText += "; domain=" + domain;
            }
            if(secure){
                cookieText += "; secure=" + secure;
            }
        } else {
            cookieText += "; expires="+(newDate(0)).toGMTString();
        }
        document.cookie = cookieText;
    },
    
    unset: function(name, subName, path, domain, secure){
        var subcookies = this.getAll(name);
        if(subcookies){
            delete subcookies[subName];
            this.set(name, subcookies, null, path, domain, secure);
        }
    },
    
    unsetAll: function(name, path, domain, secure){
        this.setAll(name, null, new Date(0), path, domain, secure);
    }
};

关于cookie的思考

  • 操作cookie的时候需要密切关注cookie的长度,以防超过单个cookie的长度限制

  • 所有的cookie都会由浏览器作为请求发送,所以在cookie中存储大量信息会影响到特定域的请求性能。cookie越大,完成对服务器请求的时间就越长。尽管浏览器对cookie进行了大小限制,不过最好还是尽可能在cookie中少存储信息,以避免影响性能。

  • cookie的性质和局限性使其并不能作为存储大量信息的理想手段。


发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>