HTTP Cookie,通常直接叫做cookie,最初是在客户端用于存储会话信息的。该标准要求服务器对任意HTTP请求发送Set-Cookie HTTP头作为响应的一部分,其中包含会话信息。例如,这种服务器响应头可能如下:
HTTP/1.1 200 OK
Content-type: text/html
Set-Cookie: name=value
Other-header: other-header-value
这个HTTP响应设置以name为名称,以value为值的一个cookie,名称和值在传送时都必须是URL编码的。浏览器会存储这样的会话信息,并在这之后,通过为每个请求添加Cookie HTTP头将信息发送回服务器。如下所示:
GET /index.html HTTP/1.1
Cookie: name=value
Other-header: other-header-value
发送回服务器的额外信息可以用于唯一验证客户来自于发送的哪个请求。
限制
cookie在性质上是绑定在特定的域名下的。当设定了一个cookie后,再给创建它的域名发送请求时,都会包含这个cookie。这个限制确保了储存在cookie中的信息只能让批准的接受者访问,而无法被其他域访问。
由于cookie是存在客户端计算机上的,还加入了一些限制确保cookie不会被恶意使用,同时蛇占有太多磁盘空间。每个域的cookie总数是有限的,不过浏览器之间各有不同。
当超过单个域名限制之后还要设置cookie,浏览器就会清楚以前设置的cookie,IE和Opera会删除最近最少使用过的(LRU,Least Recently Used)cookie。Firefox看上去好像是随机决定要清楚哪个cookie,所以考虑cookie限制非常重要,以免出现不可预期的后果。
浏览器中对于cookie的尺寸也有限制。大多数浏览器都有大约4096B(加减1)的长度限制。为了最佳的浏览器兼容性,最好将整个cookie长度限制在4095B以内。尺寸限制影响到一个域下所有的cookie,而并非每个cookie单独限制。
如果尝试创建超过最大尺寸限制cookie,那么该cookie会被悄无声息的丢掉。注意,虽然一个字符通常占用一字节,但是多字节情况则有不同。
cookie的构成
cookie由浏览器保存的以下几块信息构成。
- 名称:一个唯一确定
cookie的名称。cookie名称是不区分大小写的,所以myCookie和MyCookie被认为是同一个cookie。然而,实践中最好将cookie名称看作是区分大小写的,因为某些服务器会这样处理cookie,cookie的名称必须是经过URL编码的。 - 值:储存在
cookie里的字符串值。值必须被URL编码。 - 域:
cookie对哪个域是有效的。所有向该域发送的请求中都会包含这个cookie信息。这个值可以包含子域,也可以不包含它。如果没有明确设定,那么这个域会被人做来自设置cookie的那个域。 - 路径:对于指定域中的那个路径,应该向服务器发送
cookie。例如,你可以指定cookie只有从http://www.wrox.com/books/中才能访问,那么http://www.wrox.com的页面就不会发送cookie信息,即使请求都是来自同一个域的。 - 失效时间:表示
cookie何时应该被删除的时间戳(也就是,何时应该停止向服务器发送这个cookie)。默认情况下,浏览器会话结束时即将所有cookie删除;不过也可以自己设置删除时间。这个值是GMT格式的日期,用于指定应该删除cookie的精确时间。因此,cookie可以在浏览器关闭后依然保存在用户的机器上。如果你设置的失效日期是个以前的时间,那么cookie则会被立刻删除。 - 安全标志: 指定后,
cookie只有在使用SSL连接的时候才发送到服务器。
每一段信息都作为Set-Cookie头的一部分,使用分号加空格分隔每一段,如下例所示。
HTTP/1.1 200 OK
Content-type: text/html
Set-Cookie: name=value; expires=Mon, 22-Jan-07 07:10:24 GMT; domain=.wrox.com
Other-header: other-header-value
该头信息指定了一个叫做name的cookie,它会在格林威治时间2007年1月22日7:10:24失效,同时对于www.wrox.com和wrox.com的任何子域都有效。
secure标志是cookie中唯一一个非名值对儿的部分,直接包含一个secure单词。如下:
HTTP/1.1 200 OK
Content-type: text/html
Set-cookie: name=value; domain=.wrox.com; path=/; secure
这里,创建了一个对于所有wrox.com的子域和域名下(由path参数指定的)所有页面都有效的cookie,因为设置了secure标志,这个cookie只能通过SSL连接才能传输。
尤其要注意,域、路径、失效时间和secure标志都是服务器给浏览器的指示,以指定合适应该发送cookie,这些参数并不会作为发送到服务器的cookie信息的一部分,只有名值对儿才会被发送。
JS中的cookie
在JS中处理cookie有些复杂,因为其众所周知的蹩脚接口,即BOM的document.cookie属性。这个属性的独特之处在于它会因为使用它的方式不同表现出不同的行为。当用来获取属性值时,document.cookie返回当前页面可用的(根据cookie的域、路径、失效时间和安全设置)所有cookie字符串,一系列由分号隔开的名值对儿,如下所示。
name1 = value1; name2 = value2; name3 = value3;
所有名字和值都是经过URL编码的,所以必须使用decodeURIComponent()来解码。
当用于设置值得时候,document.cookie属性可以设置为一个新的cookie字符串。这个cookie字符串会被解释并添加到现有的cookie集合中。设置document.cookie并不会覆盖cookie,除非设置的cookie的名称已经存在。设置cookie的格式如下,和Set-Cookie头中使用的格式一样。
name = value; expires = expiration_time; path = domain_path; domain = domain_name; secure
这些参数中,只有cookie的名字和值是必需的,下面是一个简单的例子。
document.cookie = 'name = Ann';
这段代码创建了一个叫name的cookie,值为Ann。当客户端每次向服务器端发送请求的时候,都会发送这个cookie,当浏览器关闭的时候,它就会被删除。虽然这段代码没问题,但因为这里恰好名称和值都无需编码,所以最好每次设置cookie时都使用encodeURIComponent()。
document.cookie = encodeURIComponent('name') + '=' + encodeURIComponent('Ann');
要给被创建的cookie指定额外的信息,只要将参数追加到该字符串,和Set-Cookie头中的格式一样,如下所示。
document.cookie = encodeURIComponent('name') + '=' + encodeURIComponent('Ann') + '; domain=.wrox.com; path=/';
HTTP专有cookie
还有一类cookie被称为“HTTP专有cookie”。HTTP专有cookie可以从浏览器或者服务器设置,但是只能从服务器端读取,因为JS无法获取HTTP专有cookie的值。
由于所有的cookie都会由浏览器作为请求头发送,所以在cookie中存储大量信息会影响到特定域的请求性能。cookie信息越大,完成对服务器请求的时间也就越长。尽管浏览器对cookie进行了大小限制。不过最好还是尽可能在cookie中少存储信息,以避免影响性能。
Tips
一定不要在cookie中存储重要和敏感的数据。cookie数据并非存储在一个安全环境中,其中包含的任何数据都可以被他人访问。所以不要在cookie总存储如信用卡号或者个人地址之类的数据。