会话跟踪技术:
在Web应用程序中,我们经常要跟踪用户身份。例如:当一个用户登录成功后,如果他继续访问其他页面,Web程序如何才能识别出该用户身份?当一个用户在操作自己的购物车时,Web程序如何才能识别出该用户身份?
因为HTTP协议是一个无状态协议,即Web应用程序无法区分收到的两个HTTP请求是否是同一个浏览器发出的。这就需要用到会话跟踪技术了,为了跟踪用户状态,服务器可以向浏览器分配一个唯一ID,并以Cookie的形式发送到浏览器,浏览器在后续访问时总是附带此Cookie,这样,服务器就可以识别用户身份。
即:
- 客户端第一次发送请求给服务器,服务器会获取session,如果获取不到,则创建新的,然后响应给客户端
- 下次客户端给服务器发请求时,会把sessionID带给服务器,那么服务器就能获取到了,那么服务器就判断这一次请求和上次某次请求是同一个客户端,从而能够区分开客户端
Session
我们把这种基于唯一ID识别用户身份的机制称为Session。每个用户第一次访问服务器后,会自动获得一个Session ID。如果用户在一段时间内没有访问服务器(Tomcat的默认事件为30分钟),那么Session会自动失效,下次即使带着上次分配的Session ID访问,服务器也认为这是一个新用户,会分配新的Session ID。一次Session会话中往往包含着若干次request请求。
JavaEE的Servlet机制内建了对Session的支持。当我们需要获取Session时,可以通过request请求对象的getSession()方法。例如:
HttpSession session = request.getSession();
获取HttpSession后,常见的操作方法有:
- void setAttribute(String name, Object value):将指定Key-Value键值对,存入当前Session会话中。
- Object getAttribute(String name):按照指定的Key从当前Session会话中获取Value,返回值为Object类型的对象,如果不存在,则返回null。
- void removeAttribute(String name):按照指定的Key从当前Session会话中删除Key-Value键值对。
- long getCreationTime():获取当前Session会话的创建时间。
- long getLastAccessedTime():获取当前Session会话最后一次请求的访问时间。
- String getId():获取当前Session会话的SESSION ID。
服务器识别Session的关键就是依靠一个名为JSESSIONID的Cookie。在Servlet中第一次调用req.getSession()时,Servlet容器自动创建一个Session ID,然后通过一个名为JSESSIONID的Cookie发送给浏览器:
使用Session时,由于服务器把所有用户的Session都存储在内存中,如果遇到内存不足的情况,就需要把部分不活动的Session序列化到磁盘上,这会大大降低服务器的运行效率,因此,放入Session的数据不能太大,否则会影响服务器的运行。
Cookie
实际上,Servlet提供的HttpSession本质上就是通过一个名为"JSESSIONID"的Cookie来跟踪用户会话的。除了这个名称外,其他名称的Cookie我们可以任意使用。
创建一个新Cookie时,除了指定名称和值以外,通常需要设置setPath("/"),浏览器根据此前缀决定是否发送Cookie。如果一个Cookie调用了setPath("/user/"),那么浏览器只有在请求以/user/开头的路径时才会附加此Cookie(一般不建议设置路径)。通过setMaxAge()设置Cookie的有效期,单位为秒,最后通过resp.addCookie()把它添加到响应。
通过创建Cookie,我们可以实现在客户端浏览器中存储数据的目的,例如保存用户名和密码。在Chrome浏览器中,单个 Cookie的长度不能超过 4069 个字符(包括 name,但不包括 = 号)。
如果我们要读取Cookie,例如,在IndexServlet中,读取名为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。
总结:
- Servlet容器提供了Session机制以跟踪用户;
- 默认的Session机制是以Cookie形式实现的,Cookie名称为JSESSIONID;
- 通过读写Cookie可以在客户端存储数据;