5.5 实现会话追踪的4种方式

会话追踪的实现方式有下列4种方式:

(1)使用持续Cookies(Persistent Cookies)。

(2)重写包含额外参数的URL(URL Rewriting)。

(3)建立含有数据的隐藏表单字段(Hidden Form Field)。

(4)使用内建session对象。

前3种会话追踪方式是传统的做法,每种做法都有缺点。最后1种方法是目前最常用,也是最有效的解决方案,因此在本节中将把讨论重心放在第4种会话追踪方式上,然而为求彻底了解会话追踪的机制,还是先将传统的会话追踪方式做一番介绍。

5.5.1 Cookies和URL重写

Cookie是一个小小的文本文件,它是将会话信息记录在这个文本文件内,每个页面都去Cookie中提取以前的会话信息。用户请求到达服务器后,先从Cookie中取出会话信息。这样就实现了会话追踪,前面章节已经介绍过,不再赘述。

虽然Cookie强大且持续性高,但是由于有些用户因为担心Cookie对个人隐私的威胁,会关闭Cookie,一旦如此,便无法利用Cookie来达到会话追踪的功能。

URL重写是利用get方法,在URL的尾部添加一些额外的参数来达到会话追踪(session tracking)的目的,服务器将这个标识符与它所存储的有关会话的数据关联起来。URL看起来如【例5-3】所示:http://localhost:8080/ch05/jsessionid2.jsp;jsessionid=989A54B6B8DAD17453C36C 79C32748EE。

使用URL重写的优点是Cookie被禁用或者根本不支持的情况下依旧能够工作。但也有很多缺点:

必须对所有指向某用户的网站的URL进行编码。

所有页面必须动态生成。

不能使用预先记录下来的URL进行访问,或者从其他网站链接进行访问。

5.5.2 隐藏表单字段

隐藏表单字段的方法,是利用HTML内的Hidden属性,把客户端的信息,在用户不察觉的情形下,偷偷地随着请求一起传送给服务器处理,这样一来,就可以进行会话跟踪的任务了。然后将重要的用户信息,如ID之类独一无二的数据,以隐藏字段的方式传送给服务器。隐藏字段的优点在于session数据传送到服务器端时,并不用像get方法,会将session数据暴露在URL之上。不过这种做法还是有它的缺点:一旦session数据存储在隐藏字段中,仍然有暴露数据的危机,因为只要用户直接查看HTML的源文件,session数据将会暴露无遗。这将造成安全上的漏洞,特别当用户数据是依赖于用户ID、密码来取得的时候,将会有被盗用的危险。

5.5.3 使用内建session对象

传统的会话追踪方式使用比较麻烦,JSP使用内建的session对象可以非常方便地实现会话追踪,JSP的会话机制基于Cookie或URL重写技术,融合了这两种技术的优点,当客户端允许使用Cookie时,内建session对象使用Cookie进行会话追踪,如果客户端禁用Cookie,则选择使用URL重写。

(1)获取session对象。例如把购物车作为属性存储在session中,在其他JSP页面中可以通过session再获得购物车。

     //在JSP 页面中可以直接使用session
     ShoppingCart cart = (ShoppingCart)session.getAttribute("cart");

内建的session对象是javax.servlet.http.HttpSession类的实例,如果在JavaBean或者Servlet中使用session就需要先从当前的request对象中取得,例如:

     //得到用户session和购物篮
     HttpSession session = request.getSession();
     ShoppingCart cart = (ShoppingCart)session.getAttribute("cart");

(2)读写session中的数据。向session中存入对象使用setAttribute方法,通过getAttribute方法读取对象。从session返回的值注意要转换成合适的类型,要注意检查结果是否为null。例如下面一段代码:

     HttpSession session = request.getSession();
     SomeClass value = (SomeClass)session.getAttribute("someID");
     if (value == null) {
     value = new SomeClass(...);
     session.setAttribute("someID", value);
     }
     doSomethingWith(value);

(3)废弃session数据。调用removeAttribute废弃session中的值,即移除与名称关联的值。调用invalidate废弃整个session,即废弃当前的session。如果用户注销离开站点,注意废弃与用户相关联的所有session。

(4)session的生命周期。由于没有办法知道HTTP客户端是否不再需要session,因此每个session都关联一个时间期限使它的资源可以被回收。

(5)服务器使用URL重写。session默认使用Cookie技术进行会话追踪,如果客户端不接受Cookie的时候,服务器可以利用URL重写的方式将sessionID作为参数附在URL后面,此时须利用response对象内的encodeURL或encodeRedirectURL方法,这两个方法首先判断Cookies是否被浏览器支持;如果支持,则参数URL被原样返回,sessionID将通过Cookies来维持。否则返回带有sessionID的URL。同时需要注意的是,将session的ID以URL的编码方式进行时,需将每一页都编码,才能保留住session的ID。如果遇到没有编码的URL,则无法进行会话跟踪。

(6)内建session对象使用示例。下面是一个记录同一用户到站次数的计数器,该实例包含一个文件sessionCounter.jsp。sessionCounter.jsp的完整程序代码如下:

sessionCounter.jsp记录单一用户每次光临的次数。首先,从session内取出accessCount的值,如果值为null,代表用户第一次光临,就将accessCount设为0,将heading设为“Welcome,Newcomer”;如果值不为null,则把accessCount的值加1,将heading设为“Welcome Back”。

sessionCounter.jsp的初次执行结果如图5-13所示。sessionCounter.jsp的多次执行结果如图5-14所示。

图5-13 sessionCounter.jsp的初次执行效果

图5-14 sessionCounter.jsp的多次执行效果