由于某次开发中遇到了cookie的坑,因此决心认真看cookie的机制,首选RFC。原文连接 rfc HTTP State Management Mechanism 1997 有点老其实。ajax
**申明:尽力翻译,非彻底翻译,有误的欢迎指正哈**
这篇文档是为HTTP request 和 response之间建立一个有状态的会话指明一个方法,并描述了两个头字段:Cookie和Set-cookie,用于携带服务端和客户端之间的状态信息。算法
FQHN(fully-qualified host name):指的是主机的FQDN(fully-qualified domain name),好比以1级域名.com 或 .uk结尾的彻底指定的域名,或者指主机的IP地址。(倾向于前者,后者不建议)
request-host:指的是客户端发出请求指向的服务器端的主机(跟端口无关),这里request-host是一个FQHN.
request-URI:指的是客户端发出请求指向的服务器端绝对路径部分。
host-name:指的是一个IP地址或者一个FQHN字符串。
domain-match:知足下面其中一种状况则A的host-name domain-match B的host-name:segmentfault
二者的host-name都是IP并彻底一致浏览器
二者的host-name都是FQDN字符串且彻底一致缓存
A的host-name是FQDN字符串而且格式为NB,其中N是一个非空字符串,B个格式是.C,而C是一个FQDN字符串。也就是说A = N.C,B = .C的状况。好比:域x.y.com就domain-match 域.y.com,而域x.y.com就不domain-match 域y.com。(这个定义对是否能使用某个域的cookie很是关键)同时要注意,A domain-match B,不能说明B domain-math A,一样须要经过这个定义来判断。安全
Set-cookie 和 Cookie这两个头字段有类似的语法。
(Set-cookie/Cookie) = av-pair *(";" av-pair)
其中:
av-pair = attr ["=" value]
attr = token
value = word
word = token | quoted-string(带引号的字符串)
这里边,token的定义得去查看HTTP/1.1 specification [RFC 2068] 。等号左右容许有空格。服务器
为了与客户端之间的会话保持状态信息,服务器端在response头中使用Set-Cookie字段,而客户端若是想保持状态信息,得在request头中加Cookie字段。服务器端若要终止这个会话,能够简单的设置Set-Cookie为Max-Age=0。
服务器端可能会包含多个Set-cookie字段,不过网关会把这些合并成一个Set-cookie字段,用逗号,分隔。cookie
Set-Cookiedom
set-cookie = "Set-Cookie:" cookies
其中
cookies = 1#cookie
cookie = NAME "=" VALUE *(";" cookie-av)
NAME = attr
VALUE = value
cookie-av = "Comment" "=" value | "Domain" "=" value | "Max-Age" "=" value | "Path" "=" value | "Secure" | "Version" "=" 1*DIGITui
NAME=VALUE:必须的,虽然VALUE严格上来讲对客户端是不透明的,然实际上经过检查Set-Cookie字段仍是能够读到的。
Comment=comment:可选,描述该Cookie的用处。
Domain=domain:可选,指定了cookie有效的域。明确指定的domain必须以.开头。
Max-Age=delta-seconds:可选,指cookie的存活时间,以秒为单位,非负数。Max-Age=0表示客户端须要当即丢弃该cookie。
Path=path:可选,指在某URL的子路径下cookie有效。
Secure:可选,(翻者注:有点难理解)查阅资料解释以下:建立的 Cookie 会被以安全的形式向服务器传输,也就是只能在 HTTPS 链接中被浏览器传递到服务器端进行会话验证,若是是 HTTP 链接则不会传递该信息,因此不会被窃取到Cookie 的具体内容。
HTTP状态管理机制 2011 补充
HttpOnly:可选,用于告诉客户端不能经过”non-HTTP“的方式获取cookie(好比浏览器的API:document.cookie)。
Version=version:必须。十进制的整数,指状态管理中cookie指向的版本。
控制缓存
若是cookie只给某一用户使用,则Set-Cookie头不能被缓存,相反则应该缓存。
根据状况,服务器端应该在response头中添加一些字段:
禁止缓存Set-Cookie头,则:Cache-control:no-cache="set-cookie"。
禁止在共享缓存中缓存私密文档:Cache-control:private。
To allow caching of a document, but to require that proxy caches (not user agent caches) validate it before returning it to the client:Cache-control:proxy-revalidata。(译者注:这条跟下面一条区别在哪里没看出)
To allow caching of a document and request that it be validated before returning it to the client (by "pre-expiring" it): Cache-control:max-age=0
HTTP/1.1服务器若是不肯定下游是否有代理,则必须设置Expires: old-date。(译者注:防止cookie被代理缓存,会产生bug)。Cache-Control指令会覆盖Expires:old-date。
客户端在接收到Set-Cookie的response头以后,会对其中可选的属性应用默认值:
Version:根据Netscape规范。
Domain:默认为request-host(不是以.开头)(译者注:服务器端有时候会不设置这个Domain,觉得到了客户端以后会设置成客户端的域名,实际上是目标服务器的域名)。
Max-Age:默认行为是若是客户端存在这个cookie,那这个cookie会被清除掉。
Path:请求URL中的path,不右边最右边的'/'。
Secure:客户端将经过一条不安全的通道发送cookie(译者注:也就是Http)。
拒绝cookie
考虑安全,若是知足下面的状况,客户端将不会保存cookie:
Path不是request-URI的前缀。
Domain的值不是以.开头或者没有内含的点(eg: .com没有,segmentfault.com有)。
request-host不 domain-match Domain的值。
request-host是个FQDN而且格式为HD,其中D是Domain的值,H是一个包含.的字符串。
举例子:
request-host = x.foo.com,Domain = .foo.com 经过。
Domain=.com 或者 Domain=.com. 不经过,由于没有内含的点.。
Domain=ajax.com 不经过,由于没有以.开头。
Cookie 管理
若是Set-Cookie中的cookie名字已经存在在客户端里,而且Domain和Path都同样,那么新的Cookie会覆盖旧的;若是新的Cookie中Max-Age=0,那么新旧cookie都会被清除掉。
因为客户端存储cookie的空间有限,因此可能会应用如LRU等算法来清除旧的cookie。
发送Cookie到服务器端
基于下面几种,客户端会在发送请求到服务器端的时候将cookie包含在request头中。
request-host
request-URI
cookie的存活时间
Cookie头的语法:
cookie = "Cookie:" cookie-version 1*((","|";") cookie-value)
其中:
cookie-value = NAME "=" VALUE";" path
cookie-version = "$Version" "=" value
NAME = attr
VALUE = value
path = "$Path" "=" value
domain = "$Domain" "=" value
同时以上属性的值有这样的要求:若是有相应的Set-Cookie response头,则cookie-version的值应该与此response中的cookie-version一致,不然为0.同理path也需一致,不然该属性会被剔除掉。同理Domain的值也需一致,不然也会被剔除掉。
请求头中能够包含哪些cookie有如下规则:
Domain:服务器端的FQHN必须domain-match Domain的值。
Path:Path的值必须是request-URI的前缀。
Max-Age:不能是已通过期了。
缓存代理服务器必须遵循下面规范:
依据缓存验证规则。
将response头(包含Set-cookie)传递到客户端。
将request头(包含Cookie)传递给服务器端。