因为HTTP协议是一个无状态协议,即Web应用程序无法区分收到的两个HTTP请求是否是同一个浏览器发出的。为了跟踪用户状态,服务器可以向浏览器分配一个唯一ID,并以Cookie的形式发送到浏览器,浏览器在后续访问时总是附带此Cookie,这样,服务器就可以识别用户身份。
我们把这种基于唯一ID识别用户身份的机制称为Session,每个用户第一次访问服务器后,会自动获得一个Session ID。如果用户在一段时间内没有访问服务器,那么Session会自动失效,下次即使带着上次分配的Session ID服务器也认为这是一个新用户,会分配新的Session ID。一次Session会话中往往包含着若干次request请求。
JavaEE的Servlet机制内建了对Session的支持。当我们需要获取Session时,可以通过request请求对象的getSession()方法:
HttpSession session = request.getSession();
获取Session后,常见的操作方法有:
服务器识别Session的关键就是依靠一个名为JSESSIONID的Cookie。
在Servlet中第一次调用req.getSession()时,Servlet容器会自动创建一个SessionI D .然后通过一个名为JSESSION的Cookie发送给浏览器:
使用Session时,由于服务器把所有用户的Session都存储在内存中,如果遇到内存不足的情况,就需要把部分不活动的Session序列化到磁盘上,这会大大降低服务器的运行效率,因此,放入Session的数据不能太大,否则会影响服务器的运行。
实际上,Servlet提供的HttpSession本质上就是通过一个名为JESSION的Cookie来跟踪用户会话的。除了这个名称外,其他名称的Cookie我们可以任意使用。
创建一个新的Cookie时,除了指定名称和值外,通常需要设置setPath("/"),浏览器根据此前缀决定是否发送Cookie。如果一个Cookie调用了setPath("/uesr/"),那么浏览器只有在请求以/user/开头的路径才会附加此Cookie。通过setMaxAge()设置Cookie有效期,单位为秒,最后通过resp.addCookie()把它添加到响应。
通过创建Cookie,我们可以实现在客户端浏览器中存储数据的目的,例如保存用户名和密码。
我们可以在浏览器看到服务器发送的Cookie:
如果我们要读取Cookie,例如:在IndexServelt中,读取名为lang的Cookie以获取用户设置的语言,可以写一个方法:
private String parseLanguageFromCookie(HttpServletRequest req) {
// 获取请求附带的所有Cookie:
Cookie[] cookies = req.getCookies();
// 如果获取到Cookie:
if (cookies != null) {
// 循环每个Cookie:
for (Cookie cookie : cookies) {
// 如果Cookie名称为lang:
if (cookie.getName().equals("lang")) {
// 返回Cookie的值:
return cookie.getValue();
}
}
}
// 返回默认值:
return "en";
}
所以 ,读取Cookie主要依靠遍历HttpServletRequest附带的所有的Cookie。
Session在服务端保存信息,Cookie在客户端保存信息,为了跟踪会话,服务器端在创建Session后,需要将SessionID交给客户端,因此在cookie中有JSessionID=value;但是它通常是保存在浏览器的内存中(因为Tomcat中设置为MaxAge为负数),并且也不能在多个浏览器之间共享。当不关闭浏览器在客户端再次请求时,这个ID随请求一起发送回来。如果关闭浏览器,那么保存该SessionID的cookie就被删除,导致sessionid丢失。无法找到先前的sessionid,服务器只能创建一个新的session。而这个时候先前的session是仍然存在的,知道超过设置的session超时时间间隔,那么服务器会清除该session。
利用Cookie进行会话,即可以保存在浏览器内存中,也可以持久化(这时sessionid也是被保存到硬盘,因为sessionid就是一个cookie中的一个键值对).当cookie存储在浏览器内存中时,只能被同一个浏览器进程所共享;但是对于保存在硬盘上的Cookie,可以在多个浏览器所共享。因此SessionId是随着Cookie的保存位置而保存。