首页 > 代码库 > 【JSP/Servlet-HTTP会话解析】

【JSP/Servlet-HTTP会话解析】


个人学习整理,如有不足之处,请不吝指教。转载请注明:@CSU-Max


Max之前的一篇关于Session 和 Cookie 的文章:cookie和session那些事

会话简介


web服务器跟踪客户状态的几种方式:
   1、在html表单中加入隐藏字段,它包含用于跟踪用户状态的数据;
   2、重写URL,及在URL中附带用户的状态信息;
   3、使用cookie来传递用于跟踪客户状态的数据;
   4、使用会话来跟踪用户状态的数据。

   会话能够把用户与同一用户发出的不同请求之间关联起来。不同用户的会话应当是相互独立的。在web开发领域,会话机制是用于跟踪用户状态的普遍解决方案。会话是指在一段时间内,单个用户与web应用的一系列交互过程。在一个会话过程中,用户可以多次请求该web应用的同一页面,也可以访问该web应用中的其他页面。

   在Servlet中有关于会话的 javax.servlet.http.HttpSession 接口,Servlet容器必须实现这一接口。当一个会话开始时,Servlet容器会创建一个HttpSession对象,将客户信息状态存储在该对象中,如购物车信息。Servlet容器为每个HttpSession对象分配一个唯一的标志符,称为SessionID。

会话的运作流程

   
   1、当一个浏览器进程第一次请求访问某个web应用中任意一个支持会话的网页(也可以设置页面不支持会话,下文有介绍),Servlet容器会试图寻找HTTP请求中表示SessionID的Cookie,由于还不存在这样的Cookie,故此时就会开启一个新的会话,Servlet容器会创建一个HttpSession对象,并为其分配一个唯一的SessionID,在返回HTTP响应结果时,Cookie会附带该SessionID。当浏览器接收到HTTP响应结果之后,会把Cookie(带有SessionID)保存在客户端。
   
   2、该浏览器进程继续访问该web应用中的任意支持会话的页面,在本次的HTTP请求中会包含带有SessionID的Cookie,Servlet容器会获取本次HTTP请求中的SessionID,该SessionID就是1中产生的,因此Servlet容器认为本次请求与上次请求处于同一个会话中,Servlet容器不会创建新的HttpSession对象,而是根据Cookie中的SessionID,找到内存中该SessionID对应的HttpSession对象。

   3、重复步骤2,在当前会话销毁之前(关于会话的销毁下文有介绍),仍是在同一个会话中进行访问,故不会产生新的HttpSession对象。

通过代码实例来了解会话机制


    在默认情况下,JSP页面都会支持会话,也可以通过代码显式控制支持会话:

<%@ page session = "true" %>


   若web组件支持会话,当客户请求访问该web组件时,Servlet容器会自动查找HTTP请求中表示SessionID的Cookie,并向HTTP响应结果中添加表示SessionID的Cookie。在此过程中,若有与SessionID对应的HttpSession对象,则Servlet容器使用该对象,若没有,则Servlet容器会创建一个新的HttpSession对象。
web组件可以访问代表当前会话的HttpSession对象。

   我们可以通过下面的实例代码来了解,新建一个web工程,在根目录下新建一个test.jsp,具体代码如下:
<%@ page language ="java" contentType="text/html; charset=utf-8"
      pageEncoding= "utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv= "Content-Type" content ="text/html; charset=utf-8">
<title> Insert title here</ title>
</head>
<body>
     <%
          Cookie[] cookies = request.getCookies();
           if (cookies == null) {
              out.println( "no cookie");
               return;
          }
           for ( int i = 0; i < cookies.length; i++) {
     %>
     <b >Cookie Name </b>
     <%=cookies[i].getName() %>
     <br >
     <b >Cookie Value </b>
     <%=cookies[i].getValue() %>
     <br >
     <b >Cookie Maxage</ b>
     <%=cookies[i].getMaxAge() %>
     <%
          }
     %>
</body>
</html>


   1、打开一个浏览器进程,第一次请求访问test.jsp页面,会返回“no cookie”。
      


   2、利用1打开的浏览器进程,再次访问test.jsp页面(即再按一次回车即可)。由于在1中,Servlet容器会向客户端发送一个包含SessionID的Cookie(上面已经讲到),所以本次的HTTP请求中会包含该Cookie,故test.jsp页面上会显示该Cookie的数据,如下图:

      


注:此处Cookie的maxage(有效期)属性值为 -1,表示该Cookie仅存在与当前的浏览器进程中,当浏览器关闭,该Cookie也就失效了,本次会话也结束了。

   3、利用1打开的浏览器进程再多次访问test.jsp页面,页面显示的数据仍如上图所示。
      

   4、重新打来一个浏览器进程,重复步骤1、2、3,会发现页面显示的Cookie Value不一样,即SessionID不一样,因为不同的浏览器进程对应不同的会话,每个会话都拥有一个唯一的SesionID。

   5、在test.jsp中加入如下代码,使test.jsp不支持会话,再重新打开一个浏览器进程,多次访问test.jsp页面,结果都是显示“no cookie”。因为test.jsp显式要求不支持会话,所以Servlet容器不会创建HttpSession对象,也不会向客户端发送表示SessionID的Cookie。

HttpSession 的会话范围

   
   会话的范围指的是浏览器端与一个web应用进行一次会话的过程。在具体实现时,会话范围与HttpSession对象的生命周期相对应,所以web组件只要共享同一个HttpSession对象,就能实现共享会话范围内的共享数据。
在HttpSession接口中关于在会话范围内存取共享数据有如下方法:
 /**
      * 向会话范围内存放共享数据
      */
     public void setAttribute(String name, Object value) {

     }

     /**
      * 返回会话范围内与name对应的共享数据
      */
     public Object getAttribute(String name) {
           return null;
     }

     /**
      * 返回会话范围内所有共享数据的name
      */
     public Enumeration getAttributeNames() {
           return null;
     }

     /**
      * 删除会话范围内与name对应的共享数据
      */
     public void removeAttribute(String name) {

     }

      
      利用以上的方法,我们就可以在会话范围内存取共享数据了:
  HttpSession session = request.getSession();
           //将username 存储到会话范围内的共享数据中
          session.setAttribute( "username", username);

           //从会话范围内读取username
          currentUser = (String) session.getAttribute("username" );


   在HttpSession接口中还有一些其他的访问会话的方法,想了解的可以自行研究。

HttpSession 的生命周期


   在以下情况下,会开启一个新的会话,即Servlet容器会创建一个新的HttpSession对象:
   1、一个浏览器进程第一次访问某个web应用中支持会话的任意一个网页。
   2、当浏览器与web应用的上一次会话被销毁后,浏览器进程再次访问web应用中支持会话的任意一个网页。

注:当浏览器进程与web应用的一次会话被销毁之后,web服务器端相应的HttpSession对象结束其生命周期。当浏览器进程再次访问该web应用时,在它的HTTP请求中的Cookie中包含了之前已被销毁的SessionID,但是此时Servlet容器无法找到次SessionID对应的HttpSession对象,故Servlet容器会创建新的HttpSession对象,开启新的会话。

   在以下情况下,会销毁一个会话,即Servlet容器会使HttpSession对象结束生命周期,并且存储在会话范围内的共享数据也会被销毁:
   1、浏览器进程终止。
   2、服务器端执行了HttpSession对象的invalidate()方法。
   3、会话过期。
   
   会话过期是指在会话开启之后,若在一段规定的时间内,用户没用和web应用进行交互,则Servlet容器会自动的销毁这个会话。HttpSession中的 setMaxInactiveInterval(int interval) 方法用于设置允许会话保持不活动状态的时间(以秒为单位),如果超过这个规定的时间,会话就会被Servlet容器销毁。若把 interval 参数设为负数,则表示会话永远不会过期。在Tomcat中,默认的会话保持不活动状态的时间是1800秒。

   当一个会话开启后,如果浏览器进程突然关闭,Servlet容器无法立即知道浏览器进程已经关闭,因此Servlet容器中的HttpSession对象不会立即结束生命周期,会话会在浏览器进程关闭之后,进入不活动状态,等到超出上述规定的时间后,会话就会因为过期而被Servlet容器销毁。

为什么要有会话过期的机制呢?
   
   我们知道,过多无用的HttpSession对象会影响web服务器的性能,销毁长期不活动的会话,可以及时释放这些HttpSession对象占用的内存空间。同时,会话过期机制也提高了web应用的安全性,防止未授权的用户访问会话。如某个用户访问某个web应用,之后并没有关闭浏览器进程,此时另一个用户使用该浏览器进程访问同一web应用,此时看到的是前一个用户的信息,这就给安全带来了隐患。


 ********************************************************************************

 **          转载请注明出处:  @CSU-Max    http://blog.csdn.net/csu_max          **     ********************************************************************************



【JSP/Servlet-HTTP会话解析】