HttpServlet中会话跟踪机制(session Tracking)

用户的活动发生在多个请求和相应之中,作为Web服务器来说,必须能够采用一种机制来惟一地标识一个用户,同时记录该用户的状态,这就是典型的Web需求里面的会话跟踪机制。

Java Servlet API利用Session来跟踪会话。利用Session,服务器可以把一个客户的所有请求联系在一起,并记住客户的操作状态。当用户第一次连接到服务器的时候,服务器为其建立一个Session,并分配给用户一个惟一的标识Session ID,以后用户每次提交请求的时候,都要将标识一起提交。服务根据标识找出特定的Session,用这个Session记录用户的状态。

这个过程就好像我们去超市购物存包的过程:一个顾客(相当于客户端)到超市购物,如果顾客需要存包的话(相当于请求Session对象),那么他可以到存包处(相当于Web服务器)去存,管理员将顾客的包放到一个柜子里(相当于建立了一个Session),然后将一个号码牌给顾客(相当于为顾客分配了一个惟一的SessionID)。当顾客下一次到存包处的时候,需要将号码牌交给管理员,管理员会根据号码牌找到相应的柜子,根据顾客的请求(HttpRequest)取出、添加、更换物品,然后将号码牌再次交给顾客。顾客每次到存包处的时候都要提供号码牌;顾客每次到存包处的时候,都要提供号码牌,存包处的管理员对顾客的每次请求都要做出响应(HttpRequest)。当然了,如果顾客不需要存包的话,上述过程也就不用发生(相当于Web服务器不用为用户建立Session对象)。

从上面的过程我们可以看出,通过在每一个请求和响应中包含Session ID,服务器就可以将一个用户和另外一个用户区别开来。在Servlet规范中,支持下列常见的三种机制:

  • Cookies
  • URL重写
  • 表单隐藏字段

下面我们分别介绍这三种机制,在这之前,我们需要了解Web服务器端是如何创建SessionID的。

当用户提交一个新的请求的时候(这里讨论的是新请求,旧请求在下面讨论机制的时候再讨论),服务器端会与其建立一个会话连接,但注意,这只是一个物理意义上的连接,此时服务器端会根据需要创建Session对象(包括SessionID和SessionInfo)。所谓“根据需要”是指,如果用户请求的页面中(如Servlet,JSP等)包含对Session对象的请求(如getSession()等),那么服务器端就会为其创建一个Session对象。而如果用户的请求页面之中始终没有对Session对象的请求,那么服务器端将不会为之创建Session对象。(JSP文件在服务器端被编译成.java的时候,服务器会预先为其创建Session内建对象;但是如果是Servlet文件的话,需要我们自己写程序主动调用Session对象)。我们可以用一个非常简单的例子程序来说明上述观点。

Servlet的文件代码如下:

  1. public void doGet(HttpServletRequest request, HttpServletResponse response)
  2.       throws ServletException, IOException {
  3.            HttpSession session = request.getSession(); // 此句根据需要注释掉
  4. }

建立一个空的JSP的文件。
再建立一个session监听器,在web.xml里面配置好,监听器的文件代码如下:

  1. public class MySessionListener implements HttpSessionListener{
  2.     public void sessionCreated(HttpSessionEvent se){
  3.     System.out.println("session创建成功");
  4.     }
  5.     public void sessionDestroyed(HttpSessionEvent se){
  6.     System.out.println("session被销毁");
  7.     }
  8. }

编译,运行。打开IE,当我们请求Servlet页面的时候,会触发监听器,console端会输出"session创建成功"字符;

打开一个新的IE,当我们请求JSP页面的时候,同样会触发监听器,console端会输出"session创建成功"字符;

此时,注释掉Servlet文件中对Session对象调用的代码,重新编译运行,再打开一个新的IE,此时我们发现,监听器并没有被触发,说明Session对象并没有被创建。

再来看看创建后的SessionID是如何进行会话跟踪的。

1、Cookies机制

(1) Cookies的定义

Cookies是一种能够让网站服务器把少量数据储存到客户端的硬盘或内存,或是从客户端的硬盘读取数据的一种技术。Cookies是当你浏览某网站时,由Web服务器置于你硬盘上的一个非常小的文本文件,它可以记录你的用户ID、密码、浏览过的网页、停留的时间等信息。当你再次来到该网站时,网站通过读取Cookies,得知你的相关信息,就可以做出相应的动作,如在页面显示欢迎你的标语,或者让你不用输入ID、密码就直接登录等等。从本质上讲,它可以看作是你的身份证。但Cookies不能作为代码执行,也不会传送病毒,且为你所专有,并只能由提供它的服务器来读取。保存的信息片断以"名/值"对(name-value pairs)的形式储存,一个"名/值"对仅仅是一条命名的数据。一个网站只能取得它放在你的电脑中的信息,它无法从其它的Cookies文件中取得信息,也无法得到你的电脑上的其它任何东西。 Cookies中的内容大多数经过了加密处理,因此一般用户看来只是一些毫无意义的字母数字组合,只有服务器的CGI处理程序才知道它们真正的含义。
Cookies可以有不同的保存时间,一个是Session Cookies,保存在内存中,另一个是Persistent Cookies,保存在用户硬盘上,可以通过调用Cookies.setAge()来设置Cookies的保存类型。如果将时间值设为负数,那么当客户端的浏览器关闭的时候,Cookies将会被删除,这是一个Session Cookies;如果设置为0,则cookie不会被保存,立刻删除无效;如果设置的时间值为正数,Cookies就会被保存到客户机器的硬盘上,并保存相应长的时间,这是一个persisitant Cookies。
(2) 服务器端设置Cookies中JSESSIONID
我们这里以Tomcat 5为例,说明Session Cookies是如何从服务器端发送到客户端的。
在Tomcat服务器端,Session的创建是通过调用org.apache.catalina.connector.Request类中的doGetSession()方法来完成的。下面我们给出这个方法的代码片段:

  1. protected Session doGetSession(boolean create){
  2.     ...
  3.     // creating a new session cookie based on that session
  4.     if(session!=null && getContext()!=null && getContext().getCookies()){
  5.         Cookie cookie = new Cookie(Globals.SESSION_COOKIE_NAME,session.getId());
  6.         configureSessionCookie(cookie);
  7.         response.addCookie(cookie);
  8.     }
  9.     ...
  10. }
  11. protected void configureSessionCookie(Cookie cookie){
  12.     cookie.setMaxAge(-1);
  13.     String contextPath=null;
  14.     if((!connector.getEmptySessionPath())&&(getContext()!=null)){
  15.         contextPath = getContext().getEncodedPath();
  16.     }
  17.     if((contextPath!=null)&&(contextPath.length()>0)){
  18.         cookie.setPath(contextPath);
  19.     }else{
  20.         cookie.setPath("/");
  21.     }
  22.     if(isSecure()){
  23.         cookie.setSecure(true);
  24.     }
  25. }

从以上代码可以看出,服务器端在创建session的时候,会将sessionID当做一个Cookie写入response中,由于设置了cookie.setMaxAge(-1),这个cookie是保存在内存中,浏览器关闭时会被销毁。这样我们每次打开两个不同的浏览器的时候,得到的session值是不一样的,而对于同一个浏览器的两个不同应用,由于共用内存空间(从任务管理器中只能看到一个"explore.exe"进程),所以访问的是同一个session。如果需要在不同的浏览器应用之间共享数据,需要设置cookie的生存周期为正数。
(3) 服务器端读取Cookies中的JSESSIONID
当用户向服务器端发送请求时,如果请求中包含对session对象的请求,服务器就会从request的cookie中取得sessionID,然后查看是否已经存在这个sessionID,如果已经存在,则通过该SessionID调用相应的的session信息,如果不存在,则为该请求重新分配一个sessonID。

2、URL重写机制
由于cookie可以被人为的禁止,必须有其它的机制以便在cookie被禁止时仍然能够把session id传递回服务器,经常采用的一种技术叫做 URL重写,就是把session id附加在URL路径的后面,附加的方式也有两种,一种是作为URL路径的附加信息,另一种是作为查询字符串附加在 URL后面。网络在整个交互过程中始终保持状态,就必须在每个客户端可能请求的路径后面都包含这个session id。

对所有的URL使用URL重写,包括超链接,form的action,和重定向的URL。每个引用你的站点的URL,以及那些返回给用户的URL(即使通过间接手段,比如服务器重定向中的Location字段)都要添加额外的信息。这意味着在你的站点上不能有任何静态的HTML页面(至少静态页面中不能有任何链接到站点动态页面的链接)。因此,每个页面都必须使用servlet 或JSP动态生成。即使所有的页面都动态生成,如果用户离开了会话并通过书签或链接再次回来,会话的信息都会丢失,因为存储下来的链接含有错误的标识信息-该URL后面的SESSION ID已经过期了。

读者也许会考虑,在开发Web应用程序的时候,如何去判断客户端是否禁用了Cookie,从而决定是否采用URL重写机制去跟踪用户的会话。实际上,客户端是否禁用了Cookie,不需要我们去判断,Servlet容易会帮我们做这件事情。我们在开发Web程序的时候,只要对所有的链接和重定向语句中的所有URL都调用encodeURL()和encodeRedirectURL()方法进行编码就行了。这两个方法在执行时,首先判断当前的Servlet是否已经执行了HttpSession的invalidate()方法,如果已经执行了,直接返回参数URL。接下来,判断客户端是否已经禁用了Cookie,如果没有禁用,则直接返回参数URL,如果禁用了Cookie,则在参数URL中附加SessionID,返回编码后的URL。
了解了encodeURL()和encodeRedirectURL()方法的工作原理以后,就可以结合基于cookie和URL重写的机制来跟踪用户对话。如果一个Web应用程序的功能实现依赖于某个用户会话的跟踪,那么你可以将所有的页面实现为动态的,并在代码中使用URL重写机制。在运行时,Servlet容易就会自动根据客户端的情况来选择会话跟踪机制。

3、表单隐藏字段
就是服务器会自动修改表单,添加一个隐藏字段,以便在表单提交时能够把session id传递回服务器。比如下面的表单:

  1. <form name="testform" action="/xxx">
  2. <input type="text">
  3. </form>

在被传递给客户端之前将被改写成:

  1. <form name="testform" action="/xxx">
  2. <input type="hidden" name="jsessionid" value="ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764">
  3. <input type="text">
  4. </form>

好了,三种机制就讨论到这儿,我们再来说说Session的生命周期。每个Session对象都会有特定的生命周期。Session的超时时间间隔可以通过HttpSession接口的setMaxInactiveInterval()方法设置,也可以利用Web服务器的配置文件(web.xml)来设定:


  1. <session-config>
  2.     <session-timeout>5</session-timeout>
  3. </session-config>

Tomcat服务器的session超时间隔在%CATALINA_HOME%/conf/web.xml文件中有默认设置,默认为30分钟。

session在下列情况下被删除:
A.程序调用HttpSession.invalidate()
B.距离上一次收到客户端发送的session id时间间隔超过了session的最大有效时间
C.服务器进程被停止

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值