Cookie机制
Cookie
机制
1. Cookie
解决的问题
Cookie
技术是客户端的解决方案,Cookie
就是由服务器发给客户端的特殊信息,而这些信息以文本文件的方式存放在客户端,然后客户端每次向服务器发送请求的时候都会带上这些特殊的信息。
当用户使用浏览器访问一个支持Cookie的网站的时候,用户会提供包括用户名在内的个人信息并且提交至服务器;接着,服务器在向客户端回传相应的超文本的同时也会发回这些个人信息,当然这些信息并不是存放在HTTP
响应体Response Body
中的,而是存放于HTTP
响应头Response Header
中,当客户端浏览器接收到来自服务器的响应之后,浏览器会将这些信息存放在一个统一的位置。
自此,客户端再向服务器发送请求的时候,都会把相应的Cookie
再次发回至服务器。而这次,Cookie
信息则存放在HTTP
请求头Request Header
了。
有了Cookie
这样的技术实现,服务器在接收到来自客户端浏览器的请求之后,就能够通过分析存放于请求头的Cookie
得到客户端特有的信息,从而动态生成与该客户端相对应的内容。
在程序中,会话跟踪是很重要的事情。理论上,一个用户的所有请求操作都应该属于同一个会话,而另一个用户的所有请求操作则应该属于另一个会话,二者不能混淆。而Web
应用程序是使用HTTP
协议传输数据的。HTTP
协议是无状态的协议。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。这就意味着服务器无法从连接上跟踪会话。
Cookie
就是这样的一种机制。它可以弥补HTTP
协议无状态的不足。在Session
出现之前,基本上所有的网站都采用Cookie
来跟踪会话。
2. Cookie
定义
Cookie
实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用response
向客户端浏览器颁发一个Cookie
。客户端浏览器会把Cookie
保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie
一同提交给服务器。服务器检查该Cookie
,以此来辨认用户状态。服务器还可以根据需要修改Cookie
的内容。
有两个http
头部是专门负责设置以及发送cookie
的,它们分别是Set-Cookie
以及Cookie
。当服务器返回给客户端一个http
响应信息时,其中如果包含Set-Cookie
这个头部时,意思就是指示客户端建立一个cookie
,并且在后续的http
请求中自动发送这个cookie
到服务器端,直到这个cookie
过期。如果cookie
的生存时间是整个会话期间的话,那么浏览器会将cookie
保存在内存中,浏览器关闭时就会自动清除这个cookie
。另外一种情况就是保存在客户端的硬盘中,浏览器关闭的话,该cookie
也不会被清除,下次打开浏览器访问对应网站时,这个cookie
就会自动再次发送到服务器端。
一个cookie
的设置以及发送过程分为以下四步:
- 客户端发送一个
http
请求到服务器端 - 服务器端发送一个
http
响应到客户端,其中包含Set-Cookie
头部 - 客户端发送一个
http
请求到服务器端,其中包含Cookie
头部 - 服务器端发送一个
http
响应到客户端
![cookie interactive step][1]
Java
中把Cookie
封装成了javax.servlet.http.Cookie
类。每个Cookie
都是该Cookie类
的对象。服务器通过操作Cookie类
对象对客户端Cookie
进行操作。通过request.getCookie()
获取客户端提交的所有Cookie
(以Cookie[]
数组形式返回),通过response.addCookie(Cookie cookie)
向客户端设置Cookie
。
Cookie对象
使用key-value
属性对的形式保存用户状态,一个Cookie对象
保存一个属性对,一个request
或者response
同时使用多个Cookie
。因为Cookie类
位于包javax.servlet.http.*
下面,所以JSP
中不需要import
该类。
3. 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
做了特殊处理。本章后面也会对Cookie
做类似的处理。
4. Cookie
的属性设置
除了name
与value
之外,Cookie
还具有其他几个常用的属性。每个属性对应一个getter
方法与一个setter
方法。
String name
:该Cookie
的名称。Cookie
一旦创建,名称便不可更改。Object value
:该Cookie
的值。如果值为Unicode
字符,需要为字符编码。如果值为二进制数据,则需要使用BASE64
编码。int maxAge
:该Cookie
失效的时间,单位秒。如果为正数,则该Cookie
在maxAge
秒之后失效。如果为负数,该Cookie
为临时Cookie
,关闭浏览器即失效,浏览器也不会以任何形式保存该Cookie
。如果为0
,表示删除该Cookie
。默认为–1
。boolean secure
:该Cookie
是否仅被使用安全协议传输。安全协议。安全协议有HTTPS
,SS
L等,在网络上传输数据之前先将数据加密。默认为false
。String path
:该Cookie
的使用路径。如果设置为/sessionWeb/
,则只有contextPath
为/sessionWeb
的程序可以访问该Cookie
。如果设置为/
,则本域名下contextPath
都可以访问该Cookie
。注意最后一个字符必须为/
。String domain
:可以访问该Cookie
的域名。如果设置为.google.com
,则所有以google.com
结尾的域名都可以访问该Cookie
。注意第一个字符必须为.
。String comment
:该Cookie
的用处说明。浏览器显示Cookie
信息的时候显示该说明。int version
:该Cookie
使用的版本号。0
表示遵循Netscape
的Cookie
规范,1
表示遵循W3C
的RFC 2109
规范。
4.1 Cookie
的有效期
Cookie
的maxAge
决定着Cookie
的有效期,单位为秒Second
。Cookie
中通过getMaxAge()
方法与setMaxAge(int maxAge)
方法来读写maxAge
属性。 如果maxAge
属性为正数,则表示该Cookie
会在maxAge
秒之后自动失效。浏览器会将maxAge
为正数的Cookie
持久化,即写到对应的Cookie
文件中。无论客户关闭了浏览器还是电脑,只要还在maxAge
秒之前,登录网站时该Cookie
仍然有效。下面代码中的Cookie
信息将永远有效。
Cookie cookie = new Cookie("username","helloweenvsfei"); // 新建Cookie
cookie.setMaxAge(Integer.MAX_VALUE); // 设置生命周期为MAX_VALUE
response.addCookie(cookie); // 输出到客户端
如果maxAge
为负数,则表示该Cookie
仅在本浏览器窗口以及本窗口打开的子窗口内有效,关闭窗口后该Cookie
即失效。maxAge
为负数的Cookie
,为临时性Cookie
,不会被持久化,不会被写到Cookie
文件中。Cookie
信息保存在浏览器内存中,因此关闭浏览器该Cookie
就消失了。Cookie
默认的maxAge
值为–1
。
如果maxAge
为0
,则表示删除该Cookie
。Cookie
机制没有提供删除Cookie
的方法,因此通过设置该Cookie
即时失效实现删除Cookie
的效果。失效的Cookie
会被浏览器从Cookie
文件或者内存中删除:
Cookie cookie = new Cookie("username","helloweenvsfei"); // 新建Cookie
cookie.setMaxAge(0); // 设置生命周期为0,不能为负数
response.addCookie(cookie); // 必须执行这一句
response
对象提供的Cookie
操作方法只有一个添加操作add(Cookie cookie)
。要想修改Cookie
只能使用一个同名的Cookie
来覆盖原来的Cookie
,达到修改的目的。删除时只需要把maxAge
修改为0即可。
注意:从客户端读取Cookie
时,包括maxAge
在内的其他属性都是不可读的,也不会被提交。浏览器提交Cookie
时只会提交name
与value
属性。maxAge
属性只被浏览器用来判断Cookie
是否过期。
4.2 Cookie
的修改、删除
Cookie
并不提供修改、删除操作。如果要修改某个Cookie
,只需要新建一个同名的Cookie
,添加到response
中覆盖原来的Cookie
。如果要删除某个Cookie
,只需要新建一个同名的Cookie
,并将maxAge
设置为0
,并添加到response
中覆盖原来的Cookie
。注意是0
而不是负数。负数代表其他的意义。读者可以通过上例的程序进行验证,设置不同的属性。
注意:修改、删除Cookie
时,新建的Cookie
除value
、maxAge
之外的所有属性,例如name
、path
、domain
等,都要与原Cookie
完全一样。否则,浏览器将视为两个不同的Cookie
不予覆盖,导致修改、删除失败。
4.3 Cookie
的域名
Cookie
是不可跨域名的。域名www.google.com
颁发的Cookie
不会被提交到域名www.baidu.com
去。这是由Cookie
的隐私安全机制决定的。隐私安全机制能够禁止网站非法获取其他网站的Cookie
。
正常情况下,同一个一级域名下的两个二级域名如www.helloweenvsfei.com
和images.helloweenvsfei.com
也不能交互使用Cookie
,因为二者的域名并不严格相同。如果想所有helloweenvsfei.com
名下的二级域名都可以使用该Cookie
,需要设置Cookie
的domain
参数。
Cookie cookie = new Cookie("time","20080808"); // 新建Cookie
cookie.setDomain(".helloweenvsfei.com"); // 设置域名
cookie.setPath("/"); // 设置路径
cookie.setMaxAge(Integer.MAX_VALUE); // 设置有效期
response.addCookie(cookie); // 输出到客户端
4.4 Cookie
的路径
domain
属性决定运行访问Cookie
的域名,而path
属性决定允许访问Cookie
的路径ContextPath
。
如果只允许/sessionWeb/
下的程序使用Cookie
:
Cookie cookie = new Cookie("time","20080808"); // 新建Cookie
cookie.setPath("/session/"); // 设置路径
response.addCookie(cookie); // 输出到客户端
设置为/
时允许所有路径使用Cookie
。path
属性需要使用符号/
结尾。name
相同但domain
不同的两个Cookie
也是两个不同的Cookie
。
页面只能获取它属于的Path的Cookie。例如/session/test/a.jsp不能获取到路径为/session/abc/的Cookie。使用时一定要注意。
domain
表示的是cookie
所在的域,默认为请求的地址,如网址为www.test.com/test/test.aspx
,那么domain
默认为www.test.com
。而跨域访问,如域A
为t1.test.com
,域B
为t2.test.com
,那么在域A
生产一个令域A
和域B
都能访问的cookie
就要将该cookie
的domain
设置为.test.com
;如果要在域A
生产一个令域A
不能访问而域B
能访问的cookie
就要将该cookie
的domain
设置为t2.test.com
。path
表示cookie
所在的目录,默认为/
,就是根目录。在同一个服务器上有目录如下:/test/
,/test/cd/
,/test/dd/
,现设一个cookie1
的path
为/test/
,cookie2
的path
为/test/cd/
,那么test
下的所有页面都可以访问到cookie1
,而/test/
和/test/dd/
的子页面不能访问cookie2
。这是因为cookie
能让其path
路径下的页面访问。浏览器会将
domain
和path
都相同的cookie
保存在一个文件里,cookie
间用*
隔开。
4.5 Cookie
的安全属性
HTTP
协议不仅是无状态的,而且是不安全的。使用HTTP
协议的数据不经过任何加密就直接在网络上传播,有被截获的可能。使用HTTP
协议传输很机密的内容是一种隐患。如果不希望Cookie
在HTTP
等非安全协议中传输,可以设置Cookie
的secure
属性为true
。浏览器只会在HTTPS
和SSL
等安全协议中传输此类Cookie
。
Cookie cookie = new Cookie("time", "20080808"); // 新建Cookie
cookie.setSecure(true); // 设置安全属性
response.addCookie(cookie); // 输出到客户端
secure
属性并不能对Cookie
内容加密,因而不能保证绝对的安全性。如果需要高安全性,需要在程序中对Cookie
内容加密、解密,以防泄密。
Cookie
是保存在浏览器端的,因此浏览器具有操作Cookie
的先决条件。浏览器可以使用脚本程序如JavaScript
或者VBScript
等操作Cookie
。