Session与Cookie的作用都是为了保持访问用户与后端服务器的交互状态。它们各有优缺点。
Cookie:
Cookie的作用通俗地讲就是当一个用户通过HTTP访问一个服务器时,这个服务器会将一些键值对返回给客户端浏览器,并给这些数据加上一些限制条件,在条件符合时这个用户下次访问这个服务器时,数据又被完整地带回给服务器。
由于HTTP是一种无状态的协议,当用户第一次访问请求结束后,后端服务器就无法知道下一次访问的是不是同一用户。Cookie作用正是解决这个问题的。
Cookie现在有两个版本,Version 0和Version 1。两个版本的属性项有区别,可以查看相关文档。
服务端创建Cookie:
服务端可以像下面这样创建Cookie:
String getCookie(Cookie[] cookies, String key){ if(cookies!=null) for(Cookie cookie:cookies) if(cookie.getName().equals(key)) return cookie.getValue(); return null;}@Overridepublic void doGet(HttpServletRequest request,HttpServletResponse response) throws IOExpection,ServletException{ Cookie[] cookies = request.getCookies(); String userNmae = getCookie(cookies,"userName"); String userAge = getCookie(cookies,"userAge"); if(userName == null) response.addCookie(new Cookie("userName","Dabao")); if(userAge == null) response.addCookie(new Cookie("userAge ","20")); response.getHeaders("Set-Cookie");}
Cookie创建好之后,如何把它加到HTTP的Header中传给客户端?以Tomcat为例,调用generateCookieString方法将Cookie对象构造成一个字符串,构造的字符串形式如:userName="Dabao"。然后将这个字符串命名为Set-Cookie添加到MimeHeaders中。
正如上面的代码,当我们调用addCookie方法创建多个Cookie时,这些Cookie最终是在一个Header项中还是每个作为一个独立的Header项?答案是后者。每次调用addCookie时,都会创建一个Header。那么在返回给客户端浏览器时构造HTTP响应头的时候这些Header会合并吗?答案是不会。看一下Tomcat构造Http响应头的代码就明白了:
int size = headers.size();for(int i=0;i
从客户端获取Cookie:
当我们请求某个URL时,浏览器会根据这个URL路径将符合条件的Cookie放在Request请求头中传回给服务器端,服务器根据request.getCookies()来获取所有的Cookies。
Session:
Cookie可以让服务端跟踪每个客户端的访问,但每次访问客户端都要将Cookie传回服务端,如果Cookie很多,就增加了传输量,而Session就是为了解决这个问题出现的。
同一个客户端每次和服务端交互时,不需要每次都传回所有的Cookie,而只需要传回一个ID,这个ID是客户端第一次访问服务端生成的,而且每个客户端是唯一的。这样每次访问服务端就只需要传回ID就可以了。
有了Session ID,服务端就可以创建HttpSession对象了。第一次出发通过request.getSession()方法,如果当前ID没有相应的HttpSession对象,就创建新对象并加入到org.apache.catalina.Manager的sessions容器中保存。Manager类将管理所有的Session的生命周期,只要HttpSession对象存在,用户就可以根据Session ID来获取这个对象。
持久化Session: 当Servlet容器重启或关闭时,Standard负责持久化没有过期的StandardSession对象,它会将所有StandardSession对象持久化到一个以“SESSIONS.ser”为文件名的文件中。到Servlet重启时,也就是StandardManager初始化时,它会重新读取这个文件,解析出所有Session对象,重新保存在StandardManager的sessions集合中。注意:当Servlet容器关闭时,StandardManager类会调用unload方法持久化对象,所以Servlet必须是通过stop方法关闭的,而不是直接结束(kill)Servlet容器的进程,否则不发持久化。
Session肯定不是永久存储在服务器端的,每个session都有一个有效时间,超过有效时间就会被清除。检查每个Session是否失效是在Tomcat的一个后台线程中进行的。
除了后台线程检查失效外,调用request.getSession()时也会检查该Session是否还有效。值得注意的是,request.getSession()方法调用的Session永远会存在,因为如果之前的失效了就会创建一个新的。但以前设置的Session值将会丢失。