由于HTTP协议是无状态的协议,一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换需要建立新的连接。也就是说服务器无法从连接上跟踪会话,比如用户A购买了一件商品放入购物车,当再次购买时服务器已经无法判断该行为是否仍然属于用户A。引入Cookie机制则是为了弥补HTTP协议这一不足。

Cookie实际上是一小段文本信息,为纯文本格式不包含任何可执行代码。当客户端向服务端发出请求时,如果服务端需要记录该用户状态,就会使用response向客户端浏览器颁发一个Cookie。浏览器会将Cookie保存起来,当浏览器再次请求该网站时,浏览器便会把请求的网址连同该Cookie一起提交给服务器,服务器通过检查该Cookie来辨认用户状态,并且根据需要修改Cookie内容。

本质上cookies就是http的一个扩展,有两个http头部是专门负责设置以及发送cookie的,它们分别是Set-Cookie以及Cookie。当服务器返回给客户端一个http响应信息时,其中如果包含Set-Cookie这个头部时,意思就是指示客户端建立一个cookie,并且在后续的http请求中自动发送这个cookie到服务器端,直到这个cookie过期。如果cookie的生存时间是整个会话期间的话,那么浏览器会将cookie保存在内存中,浏览器关闭时就会自动清除这个cookie。另外一种情况就是保存在客户端的硬盘中,浏览器关闭的话,该cookie也不会被清除,下次打开浏览器访问对应网站时,这个cookie就会自动再次发送到服务器端。

一个cookie的设置以及发送过程分为以下四步:

"Cookie建立过程"

  • 客户端发送一个http请求到服务器端
  • 服务器端发送一个http响应到客户端,其中包含Set-Cookie头部
  • 客户端发送一个http请求到服务器端,其中包含Cookie头部
  • 服务器端发送一个http响应到客户端

Cookie的大小一般不超过4KB,超过这个长度的Cookie将被忽略。Cookie主要保存的信息有: + Cookie的名字 + Cookie的值 + 到期时间 + 所属域名(默认是当前域名) + 生效的路径(默认是当前网址)

Cookies保存在客户端中,按在客户端中的存储位置,可分为内存Cookie(Session Cookie)和硬盘Cookie。内存Cookie由浏览器维护,保存在内存中,浏览器关闭后就消失了,其存在时间是短暂的。硬盘Cookie保存在硬盘里,有一个过期时间,若要删除cookies用户手工清理的方式或到了过期时间,否则硬盘Cookie不会被删除,其存在时间是长期的。所以,按存在时间,可分为非持久Cookie和持久Cookie。此外若是Cookie中设置了Secure标志,则只能通过安全连接传输(例如,https),不能通过非安全连接传输(例如,http)Cookie,这样就不太可能被窃取,称为安全Cookie。

很多网站都会使用Cookie。例如,Google会向客户端颁发Cookie,Baidu也会向客户端颁发Cookie。那浏览器访问Google会不会也携带上Baidu颁发的Cookie呢?或者Google能不能修改Baidu颁发的Cookie呢?

答案是否定的。Cookie具有不可跨域名性。根据Cookie规范,浏览器访问Google只会携带Google的Cookie,而不会携带Baidu的Cookie。Google也只能操作Google的Cookie,而不能操作Baidu的Cookie。

Cookie在客户端是由浏览器来管理的。浏览器能够保证Google只会操作Google的Cookie而不会操作Baidu的Cookie,从而保证用户的隐私安全。浏览器判断一个网站是否能操作另一个网站Cookie的依据是域名。Google与Baidu的域名不一样,因此Google不能操作Baidu的Cookie。

需要注意的是,虽然网站images.google.com与网站www.google.com同属于Google,但是域名不一样,二者同样不能互相操作彼此的Cookie。

注意:用户登录网站www.google.com之后会发现访问images.google.com时登录信息仍然有效,而普通的Cookie是做不到的。这是因为Google做了特殊处理。

  • value属性

    value属性是必需的,它是一个键值对,用于指定Cookie的值。

  • expires属性

    expires属性用于指定Cookie过期时间。它的格式采用Date.toUTCString()的格式。如果不设置该属性,或者设为null,Cookie只在当前会话(session)有效,浏览器窗口一旦关闭,当前Session结束,该Cookie就会被删除。浏览器根据本地时间,决定Cookie是否过期,由于本地时间是不精确的,所以没有办法保证Cookie一定会在服务器指定的时间过期。

  • domain属性

    domain属性指定Cookie所在的域名,比如example.com或.example.com(这种写法将对所有子域名生效)、subdomain.example.com。如果未指定,默认为请求的地址。所指定的域名必须是当前发送Cookie的域名的一部分,比如当前访问的域名是example.com,就不能将其设为google.com。只有访问的域名匹配domain属性,Cookie才会发送到服务器。

  • path属性

    path表示cookie所在的目录,默认为/,就是根目录。必须是绝对路径(比如/、/mydir),如果未指定,默认为请求该Cookie的网页路径。只有path属性匹配向服务器发送的路径,Cookie才会发送。这里的匹配不是绝对匹配,而是从根路径开始,只要path属性匹配发送路径的一部分,就可以发送。比如,path属性等于/blog,则发送路径是/blog或者/blogroll,Cookie都会发送。path属性生效的前提是domain属性匹配。

    在同一个服务器上有目录如下:/test/,/test/cd/,/test/dd/,现设一个cookie1的path为/test/,cookie2的path为/test/cd/,那么test下的所有页面都可以访问到cookie1,而/test/和/test/dd/的子页面不能访问cookie2。这是因为cookie能让其path路径下的页面访问。

  • secure

    secure属性用来指定Cookie只能在加密协议HTTPS下发送到服务器。该属性只是一个开关,不需要指定值。如果通信是HTTPS协议,该开关自动打开。

  • max-age

    max-age属性用来指定Cookie有效期,比如60 * 60 * 24 * 365(即一年31536e3秒)

  • HttpOnly

    HttpOnly属性用于设置该Cookie不能被JavaScript读取.(即document.cookie不会返回这个Cookie的值),只用于向服务器发送。

    1
    
    Set-Cookie: key=value; HttpOnly

    上面的这个Cookie将无法用JavaScript获取。进行AJAX操作时,XMLHttpRequest对象也无法包括这个Cookie。这主要是为了防止XSS攻击盗取Cookie。

Cookie的限制

  • cookie会被附加在每个HTTP请求中,所以无形中增加了流量。
  • 由于在HTTP请求中的cookie是明文传递的,所以安全性成问题。(除非用HTTPS)
  • Cookie的大小限制在4KB左右。对于复杂的存储需求来说是不够用的。