【1】引子
在程序中,会话跟踪是很重要的事情。理论上,一个用户的所有请求操作都应该属于同一个会话,而另一个用户的所有请求操作则应该属于另一个会话,二者不能混淆。例如,用户A在超市购买的任何商品都应该放在A的购物车内,不论是用户A什么时间购买的,这都是属于同一个会话的,不能放入用户B或用户C的购物车内,这不属于同一个会话。
web应用中的会话是指一个客户端浏览器和服务器之间连续发生的一系列请求和响应的过程。
web应用中的会话状态是指web服务器与浏览器在会话过程中产生的状态信息,借助会话状态,服务器能够把属于同一会话中的一系列的请求和响应过程关联起来。
而Web应用程序是使用HTTP协议传输数据的。HTTP协议是无状态的协议。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。这就意味着服务器无法从连接上跟踪会话。即用户A购买了一件商品放入购物车内,当再次购买商品时服务器已经无法判断该购买行为是属于用户A的会话还是用户B的会话了。要跟踪该会话,必须引入一种机制。
Cookie就是这样的一种机制(在客户端保持)。它可以弥补HTTP协议无状态的不足。在Session出现之前,基本上所有的网站都采用Cookie来跟踪会话。
【2】什么是cookie
由于HTTP是一种无状态的协议,服务器单从网络连接上无从知道客户身份。怎么办呢?就给客户端们颁发一个通行证吧,每人一个,无论谁访问都必须携带自己通行证。这样服务器就能从通行证上确认客户身份了。这就是Cookie的工作原理。
Cookie实际上是一小段的文本信息。
客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。
底层实现原理:web服务器通过在http响应消息头总增加Set-Cookie响应头字段将Cookie信息发送给浏览器,浏览器则通过在http请求消息中增加Cookie请求头字段将Cookie回传给web服务器
注意:Cookie功能需要浏览器的支持。
如果浏览器不支持Cookie(如大部分手机中的浏览器)或者把Cookie禁用了,Cookie功能就会失效。不同的浏览器采用不同的方式保存Cookie。
IE浏览器会在“C:\Documents and Settings\你的用户名\Cookies”文件夹下以文本文件形式保存,一个文本文件保存一个Cookie。
浏览器一般只允许存放300个Cookie,每个站点最多存放20个Cookie,每个Cookie的大小限制为4KB。
【3】Cookie的读写
① 添加cookie
Cookie cookie = new Cookie("name","tom"); //设置有效期,单位是秒;如果不设置,则默认为会话Cookie,浏览器关闭则销毁,并不保存到磁盘 cookie.setMaxAge(1000); //将cookie插入到一个Set-Cookie HTTP响应报头中 response.addCookie(cookie);
第一次请求:
第二次请求:
② 读取cookie
<% Cookie[] cookies =request.getCookies(); if(cookies !=null && cookies.length>0){ for(Cookie cookie:cookies){ out.println(cookie.getName()+", "+cookie.getValue()); } }else{ out.println("cookie is null"); } out.println("****************************"); out.println(session); out.println(session.getId()); %>
第一次读取cookie时为null:
服务器创建session,将会将jessionid写入cookie。第二次请求时,则有了该cookie:
客户端的cookie文件可以存储若干个cookie对象的信息,在读取时,reques.getCookies()返回一个Cookie的数组,可在该数组中遍历寻找指定的Cookie对象。
Cookie并不提供修改、删除操作。
如果要修改某个Cookie,只需要新建一个同名的Cookie,添加到response中覆盖原来的Cookie。
如果要删除某个Cookie,只需要新建一个同名的Cookie,并将maxAge设置为0,并添加到response中覆盖原来的Cookie。
注意是0而不是负数。负数代表其他的意义。
注意:修改、删除Cookie时,新建的Cookie除value、maxAge之外的所有属性,例如name、path、domain等,都要与原Cookie完全一样。否则,浏览器将视为两个不同的Cookie不予覆盖,导致修改、删除失败。
【4】Cookie的生命周期
又称为有效期,生存时间,过期时间等。
cookie的内容主要包括:名字,值,过期时间,路径和域。路径与域一起构成cookie的作用范围。
两种方式设置cookie的过期时间:
① expires(未来某个时刻过期):
HttpCookie cookie=new HttpCookie("UserName"); cookie.Expires=DateTime.MinValue; //表示关闭浏览器UserName过期 Response.Cookies.Add(cookie);
② max-age(经过一定秒数过期)
Cookie cookie = new Cookie("username","tom"); //设置有效期,单位是秒 cookie.setMaxAge(1000);
若不设置过期时间,则表示这个cookie的生命期为浏览器会话期间,关闭浏览器窗口,cookie就消失。这种生命期为浏览器会话期的cookie被称为会话cookie。
会话cookie一般不存储在硬盘上而是保存在内存里,当然这种行为并不是规范规定的。
若设置了过期时间,浏览器就会把cookie保存到硬盘上(持久化cookie),关闭后再次打开浏览器,这些cookie仍然有效直到超过设定的过期时间。
在硬盘上的cookie可以在不同的浏览器进程间共享,比如两个IE窗口。而对于保存在内存里的cookie,不同的浏览器有不同的处理方式。
cookie.setMaxAge设置为0时,会马上在浏览器上删除指定的cookie cookie.setMaxAge设置为-1时,代表关闭当前浏览器即失效。
【5】Cookie的domain
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); // 输出到客户端
注意:domain参数必须以点(“.”)开始。另外,name相同但domain不同的两个Cookie是两个不同的Cookie。如果想要两个域名完全不同的网站共有Cookie,可以生成两个Cookie,domain属性分别为两个域名,输出到客户端。
【6】Cookie的path
domain属性决定运行访问Cookie的域名,而path属性决定允许访问Cookie的路径(ContextPath)。
例如,如果只允许/sessionWeb/下的程序使用Cookie,可以这么写:
Cookie cookie = new Cookie("time","20080808"); // 新建Cookie cookie.setPath("/sessionWeb/"); // 设置路径 response.addCookie(cookie); // 输出到客户端
设置为“/”时允许所有路径使用Cookie。path属性需要使用符号“/”结尾。name相同但path不同的两个Cookie也是两个不同的Cookie。
注意:页面只能获取它属于的Path的Cookie。例如/sessionWeb/test/a.jsp不能获取到路径为/sessionWeb/abc/的Cookie。使用时一定要注意。