子cookie((subcookie)介绍

为了绕开浏览器的单域名下的cookie数限制,一些开发人员使用了一种称为子cookie(subcookie)的概念。子cookie是存放在单个cookie中的更小段的数据。也就是使用cookie值来存储多个名称值对儿。子cookie最常见的格式如下所示:

name=name1=value1&name2=value2&name3=value3&name4=value4&name5=value5

子cookie一般也可以查询字符串的格式进行格式化。然后这些值可以使用单个cookie进行储存和访问,而非对每个名称-值对儿使用不同的cookie存储。最后网站或者Web应用程序可以无需达到单域名cookie上限也可以存储更加结构化的数据。

为了更好地操作子cookie,必须建立一系列新的方法。子cookie的解析和序列化会因子cookie的期望用途而略有不同并更加复杂些。例如,要获得一个子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,
            subCookies,
            i,
            parts,
            result = {};

        if (cookieStart > -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 = subCookies.length; i < len; i++) {
                    parts = subCookies[i].split("=");
                    result[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]);
                }

                return result;
            }
        }
        return null;
    },

//省略了更多的代码
};

获取子cookie的方法有两个:get()和getAll()。其中get()获取单个子cookie的值,getAll()获取所有子cookie并将它们放入一个对象中返回,对象的属性为子cookie的名称,对应值为子cookie对应的值。get()方法接收两个参数:cookie的名字和子cookie的名字。它其实就是调用getAll()获取所有的子cookie,然后只返回所需的那一个(如果cookie不存在则返回null)。

SubCookieUtil.getAll()方法和CookieUtil.get()在解析cookie值的方式上非常相似。区别在于cookie的值并非立即解码,而是先根据&字符将子cookie分割出来放在一个数组中,每一个子cookie再根据等于号分割,这样在parts数组中的前一部分便是子cookie名,后一部分则是子cookie的值。这两个项目都要使用decodeURIComponent()来解码,然后,放入result对象中,最后作为方法的返回值。如果cookie不存在,则返回null。

可以像下面这样使用上述方法:

//假设document.cookie=data=name=Nicholas&book=Professional%20JavaScript

//取得全部子cookie
var data = SubCookieUtil.getAll("data");
alert(data.name); //"Nicholas"
alert(data.book); //"Professional JavaScript"

//逐个取得子cookie
alert(SubCookieUtil.get("data", "name")); //"Nicholas"
alert(SubCookieUtil.get("data", "book")); //"Professional JavaScript"

要设置子cookie,也有两种方法:set()和setAll()。以下代码展示了它们的构造。

var SubCookieUtil = {
    set: function (name, subName, value, expires, path, domain, secure) {
        var subcookies = this.getAll(name) || {};
        subcookies[subName] = value;
        this.setAll(name, subcookies, 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 (subcookieParts.length > 0) {
            cookieText += subcookieParts.join("&");

            if (expires instanceof Date) {
                cookietext += "; expires=" + expires.toGMTString();
            }

            if (path) {
                cookieText += ";path=" + path;
            }

            if (domain) {
                cookieText += "; domain=" + domain;
            }

            if (secure) {
                cookieText += "; secure";
            }
        } else {
            cookieText += "; expires=" + (new Date(0).toGMTString());
        }
        document.cookie = cookieText;
    },

//省略了更多代码
};

这里的set()方法接收7个参数:cookie名称、子cookie名称、子cookie值、可选的cookie失效日期或时间的Date对象、可选的cookie路径、可选的cookie域和可选的布尔secure标志。所有的可选参数都是作用于cookie本身而非子cookie。为了在同一个cookie中存储多个子cookie,路径、域和secure标志必须一致;针对整个cookie的失效日期则可以在任何一个单独的子cookie写入的时候同时设置。在这个方法中,第一步是获取指定cookie名称对应的所有子cookie。逻辑或操作符”||”用于当getAll()返回null时将subcookies设置为一个新对象。然后,在subcookies对象上设置好子cookie值并传给setAll()。

而setAll()方法接收6个参数:cookie名称、包含所有子cookie的对象以及和set()中一样的4个可选参数。这个方法使用for-in循环遍历第二个参数中的属性。为了确保确实是要保存的数据,使用了hasOwnProperty()方法,来确保只有实例属性被序列化到子cookie中。由于可能会存在属性名为空字符串的情况,所以在把属性名加入结果对象之前还要检查一下属性名的长度。将每个子cookie的名值对儿都存入subcookieParts数组中,以便稍后可以使用join()方法以&号组合起来。剩下的方法则和CookieUtil.set()一样。

可以按如下方式使用这些方法:

//假设document.cokie=data=name=Nicholas&book=Professiona%20JavaScript

//设置两个cookie
SubCookieUtil.set("data", "name", "Nicholas");
SubCookieUtil.set("data", "book", "Professional JavaScript");

//设置全部子cookie和失效日期
SubCookieUtil.setAll("data", { name: "Nicholas", book: "Professional Javascript" }, new Data("January 1, 2010"));

//修改名字的值,并修改cookie的失效日期
SubCookieUtil.set("data", "name", "Michael", new Date("February 1, 2010"));

子cookie的最后一组方法是用于删除子cookie的。普通cokie可以通过将失效时间设置为过去的时间的方法来删除,但是子cookie不能这样做。为了删除一个子cookie,首先必须获取包含在某个cookie中的所有子cookie,然后仅删除需要删除的那个子cookie,然后再将余下的子cookie的值保存为cookie的值。请看以下代码。

var SubCookieUtil = {
    unset: function (name, subName, path, domain, secure) {
        var subcookies = this.getAll(name);
        if (subcookies) {
            delete subcookies[subName];
            this.setAll(name, subcookies, null, path, domain, secure);
        }
    },

    unsetAll: function (name, path, domain, secure) {
        this.setAll(name, null, new Date(0), path, domain, secure);
    }
};

这里定义的两个方法用于两种不同的目的。unset()方法用于删除某个cookie中单个子cookie而不影响其它的;而unsetAll()方法则等同于CookieUtil.unset(),用于删除整个cookie。和setAll()一样、域和secure标志必须和之前创建的cookie包含的内容一致。这两个方法可以像下面这样使用。

//仅删除名为name的子cookie
SubCookieUtil.unset("data", "name");

//删除整个cookie
SubCookieUtil.unsetAll("data");

如果你担心开发中可能会达到单域名的cookie上限,那么子cookie可是一个非常有吸引力的备选方案。不过,你需要更加密切关注cookie的长度,以防超过单个cookie的长度限制。

你可能感兴趣的:(JAVA,WEB)