转载:原文地址
早期Web开发面临的最大问题之一是如何管理状态。服务器端没有办法知道两个请求是否来自于同一个浏览器。那时的办法是在请求的页面中插入一个token,并且在下一次请求中将这个token返回(至服务器)。这就需要在form中插入一个包含token的隐藏表单域,或着在URL的qurey字符串中传递该token。这两种办法都强调手工操作并且极易出错。
cookies工作原理的基本信息在RFC2109中被规范化
cookie是什么?
一个cookie就是存储在用户主机浏览器中的一小段文本文件。
Cookies是纯文本形式,它们不包含任何可执行代码。
一个Web页面或服务器告之浏览器来将这些信息存储并且基于一系列规则在之后的每个请求中都将该信息返回至服务器。Web服务器之后可以利用这些信息来标识用户。
通过HTTP的Set-Cookie消息头,Web服务器可以指定存储一个cookie。
Set-Cookie消息的格式如下面的字符串(中括号中的部分都是可选的)
Set-Cookie:value [ ;expires=date][ ;domain=domain][ ;path=path][ ;secure]
value部分,通常是一个name=value格式的字符串。事实上有很多浏览器用自己的格式,有细微的不同。
当一个cookie存在,并且可选条件允许的话,该cookie的值会在接下来的每个请求中被发送至服务器。
cookie的值被存储在名为Cookie的HTTP消息头中,并且只包含了cookie的值,其它的选项全部被去除。
可选项只是存在于浏览器端,并不需要发给服务端。
例如: Cookie : value
如果在指定的请求中有多个cookies,那么它们会被分号和空格分开,例如:
Cookie:value1 ; value2 ; name1=value1
有效期选项(The expires option)
指定了cookie过期的时间,过期后可能会被浏览器删掉。
格式为Wdy,DD-Mon--YYYY HH:MM:SS GMT,例如:
Set-Cookie:name=Nicholas;expires=Sat, 02 May 2009 23:38:25 GMT
在没有expires选项时,cookie的寿命仅限于单一的会话中。浏览器的关闭意味这一次会话的结束,所以会话cookie只存在于浏览器保持打开的状态之下。
domain选项(The domain option)
指示cookie将要发送到哪个域或那些域中。默认情况下,domain会被设置为创建该cookie的页面所在的域名。
domain选项被用来扩展cookie值所要发送域的数量。例如:
Set-Cookie:name=Nicholas;domain=www.baidu.com
很多时候大网站存在二级域名,例如fanyi.baidu.com。cookies可能只发给对应的二级域名。
Path选项(The path option)
在请求相匹配的路径的时候,才会发送cookie
例如:
Set-Cookie:name=Nicholas;path=/blog
在这个例子中,path选项值会与/blog,/blogrool等等相匹配;任何以/blog开头的选项都是合法的。
secure选项(The secure option)
该选项只是一个标记并且没有其它的值。只有当请求是通过SSL和HTTPS创建时,才会发送。
这种cookie的内容意指具有很高的价值并且可能潜在的被破解以纯文本形式传输。例如
Set-Cookie:name=Nicholas;secure
现实中,机密且敏感的信息绝不应该在cookies中存储或传输,因为cookies的整个机制都是原本不安全的。
默认情况下,在HTTPS链接上传输的cookies都会被自动添加上secure选项。
cookie的维护和生命周期(cookie maintenance and lifecycle)
任意数量的选项都可以在单一的cookie中指定,并且这些选项可以以任何顺序存在,例如
Set-Cookie:name=Nicholas; domain=nczonline.net; path=/blog
这个cooke有四个标识符:cookie的name,domain,path,secure标记。
要想在将来改变这个cookie的值,需要发送另一个具有相同cookie name,domain,path的Set-Cookie消息头。
例如:
Set-Cooke:name=Greg; domain=nczonline.net; path=/blog
这将以一个新的值来覆盖原来cookie的值。
然而,仅仅只是改变这些选项的某一个也会创建一个完全不同的cookie,
例如:
Set-Cookie:name=Nicholas; domain=nczonline.net; path=/
在返回这个消息头后,会存在两个同时拥有“name”的不同的cookie。
如果你访问在www.nczonline.NET/blog下的一个页面,以下的消息头将被包含进来:
Cookie:name=Greg;name=Nicholas
在这个消息头中存在了两个名为“name”的cookie,path值越详细则cookie越靠前。domain-path越详细则cookie字符串越靠前。假设我在ww.nczonline.Net/blog下并且发送了另一个cookie,其设置如下:
Set-Cookie:name=Mike
那么返回的消息头现在则变为:
Cookie:name=Mike;name=Greg;name=Nicholas
由于包含“Mike”的cookie使用了域名(www.nczonline.net)作为其domain值并且以全路径(/blog)作为其path值,则它较其它两个cookie更加详细。
使用失效日期(using expiration dates)
当cookie创建时包含了失效日期,这个失效日期则关联了以name-domain-path-secure为标识的cookie。
要改变一个cookie的失效日期,必须指定同样的组合。当改变一个cookie的值时,你不必每次都设置失效日期,因为它不是cookie标识信息的组成部分。
例如:
Set-Cookie:name=Mike;expires=Sat,03 May 2025 17:44:22 GMT
现在已经设置了cookie的失效日期,所以下次我想要改变cookie的值时,我只需要使用它的名字:
Set-Cookie:name=Matt
在cookie上的失效日期并没有改变,因为cookie的标识符是相同的。实际上,只有你手工的改变cookie的失效日期,否则其失效日期不会改变。这意味着在同一个会话中,一个会话cookie可以变成一个持久化cookie(一个可以在多个会话中存在的),反之则不可。为了要将一个持久化cookie变为一个会话cookie,你必须删除这个持久化cookie,这只要设置它的失效日期为过去某个时间之后再创建一个同名的会话cookie就可以实现。
需要记得的是失效日期是以浏览器运行的电脑上的系统时间为基准进行核实的。没有任何办法来来验证这个系统时间是否和服务器的时间同步,所以当服务器时间和浏览器所处系统时间存在差异时这样的设置会出现错误。
cookie自动删除(automatic cookie removal)
cookie会被浏览器自动删除,通常存在以下几种原因:
会话cooke(Session cookie)在会话结束时(浏览器关闭)会被删除
持久化cookie(Persistent cookie)在到达失效日期时会被删除
如果浏览器中的cookie限制到达,那么cookies会被删除以为新建cookies创建空间。
对于任何这些自动删除来说,Cookie管理显得十分重要,因为这些删除都是无意识的。
Cookie限制条件(Cookie restrictions)
在cookies上存在了诸多限制条件,来阻止cookie滥用并保护浏览器和服务器免受一些负面影响。
有两种cookies的限制条件:cookies的属性和cookies的总大小。
原始的规范中限定每个域名下不超过20个cookies,早期的浏览器都遵循该规范,并且在IE7中有个更近一步的提升。
在微软的一次更新中,他们在IE7中增加cookies的限制到50个,与此同时Opera限定cookies个数为30.Safari和Chrome对与每个域名下的cookies个数没有限制。
发向服务器的所有cookies的最大数量(空间)仍旧维持原始规范中所指出的:4KB。
所有超出该限制的cookies都会被截掉并且不会发送至服务器。
Subcookies
鉴于cookie的数量限制,开发者提出的subcookies的观点来增加cookies的存储量。
Subcookies是一些存储在一个cookie的value中的一些name-value对,并且通常与以下格式类似:
name=a=b&c=d&e=f&g=h
这种方式允许在单个cookie中保存多个name-value对,而不会超过浏览器cookie的数量限制。
通过这种方式创建cookies的负面影响是,需要自定义解析方式来提取这些值,相比较而言cookies的格式会更为简单。服务器端框架已开始支持subcookies的存储。