一、会话管理
记得此次请求与之后请求之间关系的方式,基本方式有隐藏域、Cookie与URL重写的实现方式(必须自行处理对浏览器的响应,决定哪些信息必须送至浏览器,以便在之后的请求一并发送相关信息,供Web应用程序辨识请求间的关联)。
二、使用隐藏域
1、隐藏域是主动告知服务器多次请求间必要信息的方式之一。
2、使用隐藏域的方式,在关掉网页后,会遗失先前请求的信息,所以仅适用于一些简单的状态管理,如在线问卷。由于在查看网页源代码时,就可以看到隐藏域的值,因此这个方法不适合用于隐密性较高的数据。隐藏域不是Servlet/JSP实际管理会话时的机制,由浏览器主动告知必要的信息,为实现Web应用程序会话管理的基本原理。
二、使用Cookie
Web应用程序会话管理的基本方式,就是在此次请求中,将下一次请求时服务器应知道的信息,先响应给浏览器,由浏览器在之后的请求再一并发送给应用程序,这样应用程序就可以“得知”多次请求的相关数据。
1、Cookie是在浏览器存储信息学的一种方式,服务器可以响应浏览器set-cookie标头,浏览器收到这个标头与数值后,会将它以文件的形式存储在计算机上,这个文件就成为Cookie。可以设定给Cookie一个存活期限,保留一些有用的信息在客户端,如果关闭浏览器之后,再次打开浏览器并连接服服务器时,这些Cookie仍在有效期限之内,浏览器会使用Cookie标头自动将Cookie发送给服务器,服务器就可以得知一些先前浏览器请求的相关信息,所以在客户端存储的信息可以存活的更久一些(除非用户主动清除Cookie信息)。
2、Servlet本身提供了创建、设置与读取Cookie的API,如果要创建Cookie,可以使用Cookie类,创建时指定Cookie中的名称与数值,并使用HttpServletResponse的addCookie()方法在响应中新增Cookie。HTTP中Cookie的设定是通过set-cookie标头,所以必须在实际响应浏览器之前使用adddCookie()来新增Cookie实例,在浏览器输出HTML响应之后再运行addCookie()是没有作用的。
例1、Cookie cookie=new Cookie("user","caterpillar");
cookie.setMaxAge(7*24*60*60); //单位为s,所以一星期内有效。默认关闭浏览器之后Cookie就失效。
response.addCookie(cookie);
3、如果要取得浏览器上存储的Cookie,则可以从HttpServletRequest的getCookies()方法来取得,这可以取得属于该网页所属域的所有Cookie。取得Cookie对象后,可以使用Cookie的getName()与getValue()方法,分别取得Cookie的名称与数值。
例2、Cookie[] cookies=request.getCookies();
if(cookies!=null){
for(Cookie cookie:cookies){
String name=cookie.getName();
String value=cookie.getValue();
}
}
4、Cookie另一个常见的应用,就是实现用户自动登录功能。
5、Cookie类的setHttpOnly()方法,可以将Cookie标示为仅用于HTTP,这会在set-cookie标头上附加HttpOnly属性,在浏览器支持的情况下,这个Cookie将不会被客户端脚本读取,可以使用isHttpOnly()来得知一个Cookie是否被setHttpOnly()标示为仅用于HTTP。
三、使用URL重写
1、所谓URL重写,其实就是GET请求参数时的应用,当服务器响应浏览器上一次请求时,将某些相关信息以超链接方式响应给浏览器,超链接中包括请求参数信息。
2、URL重写是在超链接之后附加信息的方式,所以必须以GET方式发送请求,再加上GET本身可以携带的请求参数长度有限,因此大量的客户端信息保留,并不适合使用URL重写。
四、HttpSession会话管理
可以将会话期间必须共享的数据,保存在HttpSession中成为属性,如果用户关掉浏览器接受Cookie的功能,HttpSession也可以改用URL重写继续其会话管理功能。
1、使用HttpSession
(1)在Servlet/JSP中,如果想要进行会话管理,可以使用HttpServletRequest的getSession()方法取得HttpSession对象。
例3、HttpSession session=request.getSession();
getSession()另一个版本可以传入布尔值,默认值为true,表示若尚未存在HttpSession实例时,直接创建一个新的对象;若传入false,若尚未存在HttpSession实例,则直接返回null。
(2)HttpSession最常用的两个方法:setAttribute()与getAttribute(),可以在对象中设置及取得属性。
例4、session.setAttribute("p1",p1);
session.getAttribute("p1",p1);
(3)如果想要在浏览器与Web应用程序的会话期间,保留请求之间的相关信息,可以使用HttpSession的setAttribute()方法将相关信息设置为属性,在会话期间,就可以当作Web应用程序“记得”客户端的信息,如果想要取出这些信息,则通过HttpSession的getAttribute()就可以取出。(4)执行HttpSession的invalidata()方法之后,容器会销毁回收HttpSession对象,如果再次通过HttpServletRequest的getSession(),取得HttpSession就是另一个新对象了。
(5)HttpSession并非线程安全,所以必须注意属性设定时共享存储的问题。
2、HttpSession会话管理原理
(1)运行HttpServletRequest的getSession()时,Web容器会创建HttpSession对象,关键在于每个HttpSession对象都会有个特殊的ID,称为Session ID,可以执行HttpSession的getId()来取得Session ID。这个Session ID默认会使用Cookie存放在浏览器中。
通过getSession()取得HttpSession,是Web容器中的一个Java对象,HttpSession中存放的属性,也就存放于服务器端的Web容器之中,每个HttpSession各有特殊的Session ID,当浏览器请求应用程序时,会将Cookie中存放的Session ID一并发送给应用程序,Web容器会根据Session ID来找出对应的HttpSession对象,这样就可以取得各个浏览器个别的会话数据。
(2)使用HttpSession来进行会话管理时,设定属性的对象是存储在服务器端,而Session ID默认使用Cookie存放于浏览器端,Web容器存储Session ID的Cookie“默认”为关闭浏览器就失效,所以重新启动浏览器请求应用程序时,通过getSession()取得的是新的HttpSession对象。
(3)每次请求来到应用程序时,容器会根据发送过来的Session ID取得对应的HttpSession,由于HttpSession对象会占用内存空间,所以HttpSession的属性中尽量不要存储耗资源的大型对象,必要时将属性移除,或者不需要使用HttpSession时,执行invalidate()让HttpSession失效。
(4)默认关闭浏览器会马上失效的是浏览器的Cookie,不是HttpSession。因为Cookie失效了,就无法通过Cookie发送Session ID,所以尝试getSession()时,容器会产生新的HttpSession,要让HttpSession立即失效必须运行invalidate()方法,否则HttpSession会等到设定的失效期间过后才会被容器销毁回收。
(5)可以执行HttpSession的setMaxInactiveInterval()方法,设定浏览器多久没有请求应用程序的话,HttpSession(HttpSession对象)就自动失效,设定的单位是“秒”。
3、HttpSession与URL重写
(1)HttpSession默认使用Cookie存储Session ID,如果用户关掉浏览器接收Cookie的功能,就无法使用Cookie在浏览器存储Session ID。如果在用户禁用Cookie的情况下,仍打算运用HttpSession来进行会话管理,那么可以搭配URL重写,向浏览器响应一段超链接,超链接URL后附加Session ID,当用户单击超链接,将Session ID以GET请求发送给Web应用程序。
(2)如果要使用URL重写的方式来发送Session ID,可以使用HttpServletResponse的encodeURL()协助产生所需的URL重写。当容器尝试取得HttpSession实例时,若能从HTTP请求中取得带有Session ID的Cookie,encodeURL()会将传入的URL原封不动的输出。如果容器尝试取得HttpSession实例时,无法从HTTP请求中取得带有Session ID的Cookie时(通常是浏览器禁用Cookie的情况),encodeURL()会自动产生带有Session ID的URL重写。
(3)如果执行encodeURL(),在浏览器第一次请求网站时,容器并不知道浏览器是否禁用Cookie,所以容器的做法是Cookie(发送set-cookie标头)与URL重写的方式,因此如果Servlet有以下语句,无论浏览器有无禁用Cookie,第一次请求时,则会显示在Session ID的URL。
request.getSession();
out.println(response.encodeURL("index.jsp"));
(4)当容器尝试取得HttpSession对象时,无法从Cookie中取得Session ID,使用encodeURL()就会为产生有Session ID的URL,以便于下次单击超链接时再次发送Session ID。另一个HttpServletResponse上的encodeRedirectURL()方法,则可以在要求浏览器重定向时,在URL上显示Session ID。
(5)在HttpSession存货期间,只要有人取得当次的Session ID,在另一浏览器相同的URL附上Session ID,就可以取得同一个HttpSession对象。建议加密敏感信息,并在不使用HttpSession时执行invalidate()明确使之失效。