会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话。常用的会话跟踪技术是CookieSessionCookie通过在客户端记录信息确定用户身份Session通过在服务器端记录信息确定用户身份。本章将系统地讲述CookieSession机制,并比较说明什么时候不能用Cookie,什么时候不能用Session
1.1  Cookie机制
在程序中,会话跟踪是很重要的事情。理论上,一个用户的所有请求操作都应该属于同一个会话,而另一个用户的所有请求操作则应该属于另一个会话,二者不能混淆。例如,用户A在超市购买的任何商品都应该放在A的购物车内,不论是用户A什么时间购买的,这都是属于同一个会话的,不能放入用户B或用户C的购物车内,这不属于同一个会话。
Web应用程序是使用HTTP协议传输数据的HTTP协议是无状态的协议。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。这就意味着服务器无法从连接上跟踪会话。即用户A购买了一件商品放入购物车内,当再次购买商品时服务器已经无法判断该购买行为是属于用户A的会话还是用户B的会话了。要跟踪该会话,必须引入一种机制。
Cookie就是这样的一种机制。它可以弥补HTTP协议无状态的不足。在Session出现之前,基本上所有的网站都采用Cookie来跟踪会话。
1.1.1  什么是Cookie
Cookie意为甜饼,是W3C组织提出,最早由Netscape社区发展的一种机制。目前Cookie已经成为标准,所有的主流浏览器如IENetscape提交更改是内存条吗、FirefoxOpera等都支持Cookie
由于HTTP是一种无状态的协议,服务器单从网络连接上无从知道客户身份。怎么办呢?就给客户端们颁发一个通行证吧,每人一个,无论谁访问都必须携带自己通行证。这样服务器就能从通行证上确认客户身份了。这就是Cookie的工作原理
Cookie实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容
查看某个网站颁发的Cookie很简单。在浏览器地址栏输入javascript:alert (document. cookie)就可以了(需要有网才能查看)。JavaScript脚本会弹出一个对话框显示本网站颁发的所有Cookie的内容,如图1.1所示。
1.1  Baidu网站颁发的Cookie
1.1中弹出的对话框中显示的为Baidu网站的Cookie。其中第一行BAIDUID记录的就是笔者的身份helloweenvsfei,只是Baidu使用特殊的方法将Cookie信息加密了。
%注意:Cookie功能需要浏览器的支持。如果浏览器不支持Cookie(如大部分手机中的浏览器)或者把Cookie禁用了,Cookie功能就会失效。不同的浏览器采用不同的方式保存CookieIE浏览器会在“C:\Documents and Settings\你的用户名\Cookies”文件夹下以文本文件形式保存,一个文本文件保存一个Cookie
1.1.2  记录用户访问次数
Java中把Cookie封装成了javax.servlet.http.Cookie。每个Cookie都是该Cookie类的对象。服务器通过操作Cookie类对象对客户端Cookie进行操作。通过Cookie()获取客户端提交的所有Cookie(以Cookie[]数组形式返回),通过response.addCookie(Cookie cookie)向客户端设置Cookie
Cookie对象使用key-value属性对的形式保存用户状态,一个Cookie对象保存一个属性对,
一个request或者response同时使用多个Cookie。因为Cookie类位于包javax.servlet.http.*下面,所以JSP中不需要import该类。
1.1.3  Cookie的不可跨域名性
很多网站都会使用Cookie。例如,Google会向客户端颁发CookieBaidu也会向客户端颁发Cookie。那浏览器访问Google会不会也携带上Baidu颁发的Cookie呢?或者Google能不能修改Baidu颁发的Cookie呢?
答案是否定的。Cookie具有不可跨域名性。根据Cookie规范,浏览器访问Google只会携带GoogleCookie,而不会携带BaiduCookieGoogle也只能操作GoogleCookie,而不能操作BaiduCookie
Cookie在客户端是由浏览器来管理的。浏览器能够保证Google只会操作GoogleCookie而不会操作BaiduCookie,从而保证用户的隐私安全。浏览器判断一个网站是否能操作另一个网站Cookie的依据是域名。GoogleBaidu的域名不一样,因此Google不能操作BaiduCookie
需要注意的是,虽然网站le与网站le同属于Google,但是域名不一样,二者同样不能互相操作彼此的Cookie
%注意:用户登录网站le之后会发现访问le时登录信息仍然有效,而普通的Cookie是做不到的。这是因为Google做了特殊处理。本章后面也会对Cookie做类似的处理。
1.1.4  Unicode编码:保存中文
中文与英文字符不同,中文属于Unicode字符,在内存中占4个字符,而英文属于ASCII字符,内存中只占2个字节Cookie中使用Unicode字符时需要对Unicode字符进行编码,否则会乱码。
%提示:Cookie中保存中文只能编码。一般使用UTF-8编码即可。不推荐使用GBK等中文编码,因为浏览器不一定支持,而且JavaScript也不支持GBK编码。
1.1.5  BASE64编码:保存二进制图片
Cookie不仅可以使用ASCII字符与Unicode字符,还可以使用二进制数据。例如在Cookie中使用数字证书,提供安全度。使用二进制数据时也需要进行编码。
%注意:本程序仅用于展示Cookie中可以存储二进制内容,并不实用。由于浏览器每次请求服务器都会携带Cookie,因此Cookie内容不宜过多,否则影响速度。Cookie的内容应该少而精。
1.1.6  设置Cookie的所有属性
除了namevalue之外,Cookie还具有其他几个常用的属性。每个属性对应一个getter方法与一个setter方法。Cookie类的所有属性如表1.1所示。
1.1  Cookie常用属性
   
   
String name
Cookie的名称。Cookie一旦创建,名称便不可更改
Object value
Cookie的值。如果值为Unicode字符,需要为字符编码。如果值为二进制数据,则需要使用BASE64编码
int maxAge
Cookie失效的时间,单位秒。如果为正数,则该CookiemaxAge秒之后失效。如果为负数,该Cookie为临时Cookie,关闭浏览器即失效,浏览器也不会以任何形式保存该Cookie。如果为0,表示删除该Cookie。默认为–1
boolean secure
Cookie是否仅被使用安全协议传输。安全协议。安全协议有HTTPSSSL等,在网络上传输数据之前先将数据加密。默认为false
String path
Cookie的使用路径。如果设置为“/sessionWeb/”,则只有contextPath“/sessionWeb”的程序可以访问该Cookie。如果设置为“/”,则本域名下contextPath都可以访问该Cookie。注意最后一个字符必须为“/”
String domain
可以访问该Cookie的域名。如果设置为“.google”,则所有以“google”结尾的域名都可以访问该Cookie。注意第一个字符必须为“.”
String comment
Cookie的用处说明。浏览器显示Cookie信息的时候显示该说明
int version
Cookie使用的版本号。0表示遵循NetscapeCookie规范,1表示遵循W3CRFC 2109规范
1.1.7  Cookie的有效期
CookiemaxAge决定着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
如果maxAge0,则表示删除该CookieCookie机制没有提供删除Cookie的方法,因此通过设置该Cookie即时失效实现删除Cookie的效果。失效的Cookie会被浏览器从Cookie文件或者内存中删除,例如:
Cookie cookie = new Cookie("username", "helloweenvsfei");  // 新建Cookie
cookie.setMaxAge(0);                            // 设置生命周期为0,不能为负数