随着 Web 应用程序的出现,也产生了对于能够直接在客户端上存储用户信息能力的要求。想法很合乎逻辑,属于某个特定用户的信息应该存在该用户的机器上。无论是登录信息、偏好设定或其他数据,web应用提供者发现他们在找各种方式将数据存在客户端上。这个问题的第一个方案是以 cookie 的形式出现的,cookie 是过去 Netscape Communications 公司创造的,并在一个标题为 "持久客户端状态 -- HTTP Cookies" 的标准中被阐述。今天,cookie 只是在客户端存储数据的其中一种选项。
19.1 cookie
HTTP Cookie ,通常直接叫做 cookie ,最初是在客户端用于存储会话信息的。该标准要求服务器对任意 HTTP 请求发送 Set-Cookie HTTP 头作为响应的一部分,其中包含会话信息。例如,这种服务器响应的头可能如下:
这个 HTTP 响应设置以 name 为名称、以 value 为值的一个 cookie ,名称和值在传送时都必须是 URL 编码的。浏览器会存储这样的会话信息,并在这之后,通过为每个请求添加 Cookie HTTP 头将信息发送回服务器,如下所示:
发送回服务器的额外信息可以用于唯一验证客户来自于发送的哪个请求。
19.1.1 限制
cookie 在性质上是绑定在特定的域名下的。当设定了一个 cookie 后,再给创建它的域名发送请求时,都会包含这个 cookie 。这个限制确保了存储在 cookie 中的信息只能让批准的接受者访问,而无法被其他域访问。
由于 cookie 是存在客户端计算机上的,还加入了一些限制确保 cookie 不会被恶意使用,同时不会占据太多磁盘空间。每个域的 cookie 总数是有限的,不过浏览器之间各有不同。如下所示。
- IE6 以及更低版本限制每个域名最多 20 个 cookie。
- IE7 和之后版本每个域名最多 50 个。IE7 最初是支持每个域名最大 20 个 cookie ,之后被微软的一个补丁所更新。
- Firefox 限制每个域最多 50 个 cookie 。
- Opera 限制每个域最多 30 个 cookie 。
- Safari 和 Chrome 对于每个域的 cookie 数量限制没有硬性规定。
19.1.2 cookie 的成分
- 名称 -- 一个唯一确定 cookie 的名称。cookie 名称是大小写不敏感的,所以 myCookie 和 MyCookie 被认为是同一个 cookie。然而,实践中最好将 cookie 名称看作是大小写敏感的,因为某些服务器会这样处理 cookie 。cookie 的名称必须是经过 URL 编码的。
- 值 -- 存储在 cookie 中的字符串值。值必须被 URL 编码。
- 域 -- cookie 对于哪个域是有效的。所有向该域发送的请求中都会包含这个 cookie 信息。这个值可以包含子域 (subdomain,如 www.wrox.com) ,也可以不包含它 (如 .wrox.com,则对于 wrox.com 的所有子域都有效)。如果没有明确设定,那么这个域会被认作来自设置 cookie 的那个域。
- 路径 -- 对于指定域中的那个路径,应该向服务器发送 cookie 。例如,你可以指定 cookie 只有从 http://www.wrox.com/books/ 中才能访问,那么 http://www.wrox.com 的页面就不会发送 cookie 信息,即使请求都是来自同一个域的。
- 失效时间 -- 表示 cookie 何时应该被删除的时间戳 (也就是,何时应该停止向服务器发送这个 cookie)。默认情况下,浏览器会话结束时即将所有 cookie 删除;不过也可以自己设置删除时间。这个值是个 GMT 格式的日期 (Wdy, DD-Mon-YYYY HH:MM:SS GMT), 用于指定应该删除 cookie 的准确时间。因此,cookie 可在浏览器关闭后依然保存在用户的机器上。如果你设置的失效日期是个以前的时间,则 cookie 被立刻删除。
- 安全标志 -- 指定后,cookie 只有在使用 SSL 连接的时候才发送到服务器。例如,cookie 信息只能发送给 https://www.wrox.com,而 http://www.wrox.com 的请求则不能发送 cookie。


19.1.3 JavaScript 中的 cookie
var CookieUtil = {
get: function(name){
var cookieName = encodeURIComponent(name) + "=",
cookieStart = document.cookie.indexOf(cookieName),
cookieValue = null;
if(cookieStart > -1){
var 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){
var cookieText = encodeURIComponent(name) + "=" + encodeURIComponent(value);
if(expires instanceof Date){
cookieText += "; expires=" + expires.toGMTString();
}
if(path){
cookieText += "; path=" + path;
}
if(domain){
cookieText += "; domain=" + domain;
}
if(secure){
cookieText += "; secure";
}
document.cookie = cookieText;
},
unset: function(name, path, domain, secure){
this.set(name, "", new Date(0), path, domain, secure);
}
};
// 设置 cookie
CookieUtil.set("name", "Nicholas");
CookieUtil.set("book", "Professional JavaScript");
// 读值
alert(CookieUtil.get("name")); // "Nicholas"
alert(CookieUtil.get("book")); // "Professional JavaScript"
// 删除 cookie
CookieUtil.unset("name");
CookieUtil.unset("book");