其实这个问题回答起来既简单又复杂,简单是因为它们本身只是 HTTP 协议中的一个配置项,在 Servlet 规范中也只是对应到一个类而已;说它复杂原因在于当我们的系统大到需要用到很多 ">Cookie 的时候,我们不得不考虑 HTTP 协议对 Cookie 数量和大小的限制,那么如何才能解决这个瓶颈呢? Session 也会有同样的问题,当我们的一个应用系统有几百台服务器的时候如何解决 Session 在多台服务器之间共享?它们还有一些安全问题,如 Cookie 被盗,Cookie 伪造等问题应如何避免。本章将详细解答这些问题,同时也将分享淘宝在解决这些问题时总结的一些经验。
Session 与 Cookie 的作用都是为了保持访问用户与后端服务器的交互状态。它们有各自的优点,也有各自的缺陷,然而具有讽刺意味的是它们的优点和它们的使用场景又是矛盾的。例如,使用 Cookie 来传递信息时,随着 Cookie 个数的增多和访问量的增加,它占用的网络带宽也很大,试想假如 Cookie 占用 200 个字节,如果一天的 PV 有几亿,它要占用多少带宽?所以有大访问量的时候希望用 Session,但是 Session 的致命弱点是不容易在多台服务器之间共享,所以这也限制了 Session 的使用。
10.1 理解 Cookie
Cookie 的作用我想大家都知道,通俗地说就是当一个用户通过 HTTP 协议访问一个服务器的时候,这个服务器会将一些 Key/Value 键值对返回给客户端浏览器,并给这些数据加上一些限制条件,在条件符合时这个用户下次访问这个服务器的时候,数据又被完整地带回给服务器。
这个作用就像您去超市购物时,第一次给您办张购物卡,这个购物卡里存放了一些您的个人信息,下次您再来这个连锁超市时,超市会识别您的购物卡,下次直接购物就好了。
当初 W3C 在设计 Cookie 时实际上考虑的是为了记录用户在一段时间内访问 Web 应用的行为路径。由于 HTTP 协议是一种无状态协议,当用户的一次访问请求结束后,后端服务器就无法知道下一次来访问的还是不是上次访问的用户,在设计应用程序时,我们很容易想到两次访问是同一人访问与不同的两个人访问对程序设计和性能来说有很大的不同。例如,在一个很短的时间内,如果与用户相关的数据被频繁访问,可以针对这个数据做缓存,这样可以大大提高数据的访问性能。Cookie 的作用正是在此,由于是同一个客户端发出的请求,每次发出的请求都会带有第一次访问时服务端设置的信息,这样服务端就可以根据 Cookie 值来划分访问的用户了。
10.1.1 Cookie 属性项
当前 Cookie 有两个版本:Version 0 和 Version 1。通过它们有两种设置响应头的标识,分别是 “Set-Cookie”和“Set-Cookie2”。这两个版本的属性项有些不同,表 10-1 和表 10-2 是两个版本的属性介绍。
表 10-1.Version 0 属性项介绍
属性项 属性项介绍 NAME=VALUE 键值对,可以设置要保存的 Key/Value,注意这里的 NAME 不能和其他属性项的名字一样 Expires 过期时间,在设置的某个时间点后该 Cookie 就会失效,如 expires=Wednesday, 09-Nov-99 23:12:40 GMT Domain 生成该 Cookie 的域名,如 domain="xulingbo.net" Path 该 Cookie 是在当前的哪个路径下生成的,如 path=/wp-admin/ Secure 如果设置了这个属性,那么只会在 SSH 连接时才会回传该 Cookie
表 10-2.Version 1 属性项介绍
属 性 项 属性项介绍 NAME=VALUE 与 Version 0 相同 Version 通过 Set-Cookie2 设置的响应头创建必须符合 RFC2965 规范,如果通过 Set-Cookie 响应头设置,默认值为 0,如果要设置为 1,则该 Cookie 要
遵循 RFC 2109 规范 Comment 注释项,用户说明该 Cookie 有何用途 CommentURL 服务器为此 Cookie 提供的 URI 注释 Discard 是否在会话结束后丢弃该 Cookie 项,默认为 fasle Domain 类似于 Version 0 Max-Age 最大失效时间,与 Version 0 不同的是这里设置的是在多少秒后失效 Path 类似于 Version 0 Port 该 Cookie 在什么端口下可以回传服务端,如果有多个端口,以逗号隔开,如 Port="80,81,8080" Secure 类似于 Version 0
以上两个版本的 Cookie 中设置的 Header 头的标识符是不同的,我们常用的是 Set-Cookie:userName=“junshan”; Domain=“xulingbo.net”,这是 Version 0 的形式。针对 Set-Cookie2 是这样设置的:Set-Cookie2:userName=“junshan”; Domain=“xulingbo.net”; Max-Age=1000。但是在 Java Web 的 Servlet 规范中并不支持 Set-Cookie2 响应头,在实际应用中 Set-Cookie2 的一些属性项却可以设置在 Set-Cookie 中,如这样设置:Set-Cookie:userName=“junshan”; Version=“1”;Domain=“xulingbo.net”;Max-Age=1000。