聊聊Web应用中的Session机制:比Cookie简单但增加服务器存储压力

Session机制

聊聊Web应用中的Session机制:比Cookie简单但增加服务器存储压力

Web 应用程序中除了会使用 Cookie 来记录客户端状态外,还经常使用 Session。Session 是服务器端用来记录客户端状态的一种机制,在使用上相较于 Cookie 要简单一些,不过也相应地增加了服务器的存储压力。

Session 技术是服务端的一种解决方案,它依靠服务器来维持状态。因为 Session 这个词汇所包含的语义较为丰富,所以有必要在此明确一下 Session 的含义。其一,我们一般会将 Session 翻译为会话,这样的话,我们就可以把客户端浏览器与服务器之间一系列相互作用的动作称作一个 Session。从这个语义开始,我们会提及 Session 持续的时长,也会提及在 Session 进程中进行了何种操作等;其次,Session 意味着服务器端为客户端开辟出的存储空间,在这个空间中保存的信息是用来保持状态的。从这个语义开始考虑,我们会提及要往 Session 里存放哪些内容,以及怎样依据键值从 Session 中获取相匹配的内容等。若要使用 Session,第一步必然是创建 Session 。那么,Session 是在什么时间创建的呢?在服务器端程序运行期间创建。不同语言实现的应用程序创建 Session 的方法各不相同。在 Java 中,是通过调用 HttpServletRequest 的 getSession 方法,并将 true 作为参数来创建的。服务器在创建 Session 的同时,会生成该 Session 唯一的 Session id,这个 Session id 随后会在请求中被用来重新获取已创建的 Session;Session 创建后,就能够调用 Session 相关方法往其中增加内容,这些内容仅保存在服务器中,发到客户端的只有 Session id;当客户端再次发送请求时,会携带这个 Session id,服务器接收到请求后会依据 Session id 找到相应的 Session,进而再次使用它。正式这样一个过程,用户的状态也就得以保持了。

什么是Session

Session 是一种记录客户状态的方式。Cookie 与它不同,Cookie 保存在客户端浏览器中,而 Session 保存在服务器上。当客户端浏览器访问服务器时,服务器会以某种形式将客户端信息记录在服务器上,这就是 Session 的工作原理。当客户端浏览器再次访问时,只需从该 Session 中查找客户的状态即可。

如果把 Cookie 机制比作通过检查客户身上的“通行证”来确定客户身份,那么 Session 机制就是通过检查服务器上的“客户明细表”来确认客户身份。Session 就如同程序在服务器上建立的一份客户档案,当客户来访时,只需查询客户档案表即可。

实现用户登录

Session 所对应的类是 javax.servlet.http.HttpSession 类。每个来访者都有一个与之对应的 Session 对象,该客户的所有状态信息都被保存在这个 Session 对象当中。当客户端第一次向服务器发出请求时,就会创建出 Session 对象。Session 是一种具有 key-value 形式的属性对。可以通过 getAttribute(String key) 方法和 setAttribute(String key,Object value) 方法来读写客户的状态信息。在 Servlet 中,通过 request.getSession() 方法能够获取该客户的 Session,例如:

获取 Session 对象,通过 request.getSession() 方法来获取 HttpSession 实例,即 session 。
设置 Session 中的属性,将“loginTime”作为属性名,新的日期对象作为属性值,即 session.setAttribute("loginTime", new Date());
out.println((Date)session.getAttribute("loginTime"));  // 获取 Session 属性

request 能够通过 getSession(boolean create) 来获取 Session。其区别在于,倘若该客户的 Session 不存在,request.getSession() 这个方法会返回 null,然而 getSession(true) 则会先创建 Session 而后将其返回。

在 Servlet 中,必须借助 request 来以编程的方式获取 HttpSession 对象。而在 JSP 中,内置了 Session 隐藏对象,能够直接进行使用。倘若对其进行了声明,那么 Session 隐藏对象就无法使用了。以下的例子是利用 Session 来记录客户账号信息的。session.jsp:

<%@ page language="java" pageEncoding="UTF-8"%>




<%!
    DateFormat dateFormat = newSimpleDateFormat("yyyy-MM-dd"); // 日期格式化器
%>
<%
    response.setCharacterEncoding("UTF-8"); // 设置request编码
    Person[] persons =
    {           
       // 基础数据,保存三个人的信息
        new Person("Liu Jinghua","password1", 34, dateFormat.parse
        ("1982-01-01")),
        new Person("Hello Kitty","hellokitty", 23, dateFormat.parse
        ("1984-02-21")),
        new Person("Garfield", "garfield_pass",23, dateFormat.parse
        ("1994-09-12"))
     };
    String message = ""; // 要显示的消息
    if(request.getMethod().equals("POST"))
    { 
        // 如果是POST登录       
        for(Person person :persons)
        {           
           // 遍历基础数据,验证账号、密码
           // 如果用户名正确且密码正确
           if(person.getName().equalsIgnoreCase(request.getParameter("username"))&&person.getPassword().equals(request.getParameter("password")))
           {              
               // 登录成功,设置将用户的信息以及登录时间保存到Session
               session.setAttribute("person", person);  // 保存登录的Person
               session.setAttribute("loginTime", new Date()); // 保存登录的时间              
               response.sendRedirect(request.getContextPath() + "/welcome.jsp");
               return;
            }
        }      
        message = "用户名密码不匹配,登录失败。";  // 登录失败
    }
%>


HTML 代码是一个 FORM 表单,其具体代码暂未给出,请查看随书光盘。

登录界面会对用户的登录信息进行验证。若登录正确,会将用户信息以及登录时间保存至 Session 中。接着会转到欢迎页面 welcome.jsp 。在 welcome.jsp 中,会从 Session 中获取信息,并且将用户资料显示出来。

<%@ page language="java" pageEncoding="UTF-8"%>




<%!
    DateFormat dateFormat = newSimpleDateFormat("yyyy-MM-dd"); // 日期格式化器
%>
<%
    Person person =(Person)session.getAttribute("person");                       // 获取登录的person
    Date loginTime =(Date)session.getAttribute("loginTime");                     // 获取登录时间
%>
    // ... 部分HTML代码略
  
    
      
    
    
       
    
    
       
    
    
       
    
  
您的姓名:<%= person.getName()%>
登录时间:<%= loginTime%>
您的年龄:<%= person.getAge()%>
您的生日:<%=dateFormat.format(person.getBirthday()) %>

程序运行效果如图所示。

程序中 Session 直接保存了 Person 类对象和 Date 类对象,在使用方面比 Cookie 更便捷。多个客户端执行程序时,服务器会保存多个客户端的 Session。获取 Session 时,无需声明获取谁的 Session。Session 机制有这样的作用,当前客户只能获取到属于自己的 Session,而无法获取到他人的 Session。并且,各个客户的 Session 之间是相互独立的,彼此之间都不可见。

Session使用起来较为方便,然而,若过多的 Session 被存储在服务器内存里,就会给服务器带来压力。

Session的生命周期

Session被保存在服务器端。服务器为了能有更高的存取速度,通常会把 Session 放在内存里。每个用户都拥有一个独立的 Session。倘若 Session 的内容太过复杂,当众多客户访问服务器时,就有可能引发内存溢出的情况。所以,Session 里的信息应当尽量精简。

Session 会在用户首次访问服务器时自动创建。需要留意的是,只有在访问 JSP、Servlet 等程序时才会创建 Session,而仅仅访问 HTML、IMAGE 等静态资源是不会创建 Session 的。倘若还没有生成 Session,那么可以通过使用 request.getSession(true)来强制生成 Session。

Session 生成之后,若用户持续进行访问,那么服务器会对 Session 的最后访问时间进行更新,同时维护该 Session。每当用户访问一次服务器,不管是否对 Session 进行读写操作,服务器都将该用户的 Session 视为“活跃(active)”了一次。

Session的有效期

因为会有越来越多的用户去访问服务器,所以 Session 也会逐渐增多。为了避免出现内存溢出的情况,服务器会把在长时间内没有处于活跃状态的 Session 从内存中删除。这个时长就是 Session 的超时时间。要是超过了超时时间还没有访问过服务器,那么 Session 就会自动失去效力。

Session 的超时时间是 maxInactiveInterval 属性。可以利用对应的 getMaxInactiveInterval()来获取该超时时间。还可以通过 setMaxInactiveInterval(long interval)来修改该超时时间。

Session 的超时时间能够在 web.xml 里进行修改。同时,调用 Session 的 invalidate()方法可以让 Session 失去效力。

Session的常用方法

Session 包含着各种方法,在使用方面比 Cookie 要便捷很多。Session 的常用方法具体如下。

设置 Session 属性的方法是 setAttribute。该方法接收两个参数,一个是字符串类型的 attribute,另一个是对象类型的 value。value 参数可以是任何 Java Object,通常是 Java Bean。获取 Session ID 的方法:`getId()`:用于返回 Session 的 ID。该 ID 是由服务器自动创建的,不会出现重复的情况。long getCreationTime()这个方法可以返回 Session 的创建日期。返回类型为 long,它常常会被转化为 Date 类型。例如:有一个 Date 类型的变量 createTime,它被赋值为 new Date(session.getCreationTime())。同时,还有一个方法 long getLastAccessedTime(),该方法用于返回 Session 的最后活跃时间。获取最大非活动时间间隔的返回类型为 long int:获取 Session 的超时时间,单位是秒,超过该时间未访问,服务器就认为该 Session 失效。设置最大非活动时间间隔的函数为 void setMaxInactiveInterval(int second):用于设置 Session 的超时时间。单位为秒的 putValue 方法,参数为字符串 attribute 和对象 value,此方法不被推荐,已被 setAttribute 方法替代。获取值的方法 getValue,参数为字符串 attribute,此方法也不被推荐。void invalidate():该方法可使该 Session 失效

Tomcat 中 Session 有一个默认的超时时间,其时长为 20 分钟。能够通过 setMaxInactiveInterval(int seconds)这个方法来修改超时时间。也可以通过修改 web.xml 来改变 Session 的默认超时时间。比如将超时时间修改为 60 分钟:


   60    

参数的单位是分钟,而setMaxInactiveInterval(int s)这个方法的单位是秒。

在 server.xml 里定义 context 时,其定义方式如下(单位是秒):

Session对浏览器的要求

Session 保存在服务器,而对客户端是透明的。它的正常运行需要客户端浏览器的支持,这是因为 Session 需要使用 Cookie 作为识别标志。HTTP 协议具有无状态的特点,Session 无法通过 HTTP 连接来判断是否为同一客户。所以,服务器会向客户端浏览器发送一个名为 JSESSIONID 的 Cookie,其值为该 Session 的 id,也就是 HttpSession.getId()的返回值。而 Session 会依据这个 Cookie 来识别是否为同一用户。

该 Cookie 是由服务器自动生成的。它的 maxAge 属性通常为–1,意味着仅在当前浏览器内有效,而且各浏览器窗口之间不会共享,一旦关闭浏览器就会失效。

同一机器的两个浏览器窗口访问服务器时,会生成两个不同的 Session。然而,由浏览器窗口内的链接、脚本等打开的新窗口(非双击桌面浏览器图标等打开的窗口)除外。这类子窗口会共享父窗口的 Cookie,所以会共享一个 Session。

新开的浏览器窗口会生成新的 Session,不过子窗口除外。子窗口会与父窗口共用 Session。比如,在链接上右击,然后在弹出的快捷菜单中选择“在新窗口中打开”,此时子窗口就能访问父窗口的 Session。

如果客户端浏览器禁用了 Cookie 功能,那会怎样呢?或者客户端浏览器不支持 Cookie 又该怎么办呢?比如,绝大多数的手机浏览器都不具备支持 Cookie 的能力。而 Java Web 给出了另一种解决办法,那就是 URL 地址重写。

URL地址重写

URL 地址重写是用来解决客户端不支持 Cookie 的问题。其原理是把该用户 Session 的 id 信息写到 URL 地址里。服务器可以解析重写后的 URL 从而获取 Session 的 id。即便客户端不支持 Cookie,也能通过 Session 来记录用户状态。HttpServletResponse 类具备 encodeURL(Stringurl)这一功能,可用于实现 URL 地址的重写。例如:


    "> 
    Homepage

该方法能自动对客户端是否支持 Cookie 进行判断。若客户端支持 Cookie,就会原封不动地输出 URL。倘若客户端不支持 Cookie,就会把用户 Session 的 id 重写到 URL 里。重写后的输出或许是这样的:


    Homepage

在文件名的后面添加了字符串“;jsessionid=XXX”,此字符串位于 URL 参数的前面。其中 XXX 是 Session 的 id。经分析可知,增添的这个 jsessionid 字符串既不会对请求的文件名产生影响,也不会对提交的地址栏参数造成影响。用户单击这个链接时,会将 Session 的 id 通过 URL 提交至服务器。服务器会对 URL 地址进行解析,从而获得 Session 的 id。

如果是页面发生了重定向。那么对于 URL 地址的重写,可以按照这样的方式来写:

<%
    if(“administrator”.equals(userName)) {
        response.sendRedirect(response.encodeRedirectURL(“administrator.jsp”));
        return;
    }
%>

效果与 response.encodeURL(String url)相同:若客户端支持 Cookie,则生成原 URL 地址;若客户端不支持 Cookie,则传回重写后带有 jsessionid 字符串的地址。

大部分手机浏览器不支持 Cookie。对于 WAP 程序而言,因为这一原因,WAP 程序会采用 URL 地址重写的方式来跟踪用户会话。

TOMCAT 依据请求中是否含有 Cookie 来判断客户端浏览器是否支持 Cookie。客户端有可能支持 Cookie,然而第一次请求时不会携带任何 Cookie,因为原本就没有可携带的 Cookie,即便如此,URL 地址重写后的地址中依然会带有 jsessionid。第二次访问时,服务器已在浏览器中写入了 Cookie。所以,在 URL 地址重写后的地址里,就不会带有 jsessionid 了。

Cookie 能够被人为禁止,所以必须存在其他机制,这样在 Cookie 被禁止时,才能够将 session id 传递回服务器。一种经常被使用的技术叫 URL 重写,它是将 session id 直接添加在 URL 路径的后面。附加方式有两种,一种是作为 URL 路径的附加信息,其表现形式为;jsessionid= ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng,另一种是作为查询字符串附加在 URL 后面,表现形式为!-145788764

这两种方式对用户而言没有差别,只是服务器在解析时的处理方式不一样。采用第一种方式有助于将 session id 的信息与正常程序参数区分开。为了在整个交互过程中一直保持状态,就需要在每个客户端可能请求的路径之后都包含这个 session id。

有一种技术名为表单隐藏字段。服务器会自动对表单进行修改,添加一个隐藏的字段,这样在表单提交时就能将 session id 传递回服务器。例如下面这样的表单:

   

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

       

这种技术现在已较少应用。

在谈及 session 机制时,常常能听到这样一种错误观点:“仅关闭浏览器,session 就会消失。”其实可以设想会员卡的情形,除非顾客主动向店家提出注销卡,不然店家绝不会轻易删掉顾客的资料。对于 session 而言情况相同。如果程序未通知服务器删除一个 session,那么服务器就会一直将其保留。通常情况下,程序是在用户进行 log off 操作的时候发送一个指令来删除 session。然而浏览器不会主动在关闭之前通知服务器它将要关闭。所以服务器没有机会知道浏览器已经关闭。之所以会有这种错觉,是因为大部分 session 机制都用会话 cookie 来保存 session id。关闭浏览器后,这个 session id 就消失了。再次连接服务器时,也就无法找到原来的 session。如果使用某种手段改写浏览器发出的 HTTP 请求头,将原来的 session id 发送给服务器,那么再次打开浏览器也能够找到原来的 session。

关闭浏览器不会导致 session 被删除,这迫使服务器为 session 设置了一个失效时间。当距离客户端上一次使用 session 的时间超过这个失效时间时,服务器就可以认为客户端已经停止了活动,从而把 session 删除以节省存储空间。

Session中禁止使用Cookie

因为 WAP 上大部分的客户浏览器都不具备支持 Cookie 的能力,所以干脆禁止 Session 使用 Cookie,而统一使用 URL 地址重写会更为妥当。Java Web 规范是能够通过配置的方式来禁用 Cookie 的。接下来举例说明怎样通过配置来禁止使用 Cookie。

打开项目 sessionWeb 的 WebRoot 目录下的 META-INF 文件夹,此文件夹与 WEB-INF 文件夹处于同一级别。若该文件夹不存在,则创建它。接着打开 context.xml 文件,若该文件不存在,同样创建它。然后编辑其内容如下:/META-INF/context.xml。


    

可以对 Tomcat 全局的 conf/context.xml 进行修改,修改的内容如下:context.xml 。



    

部署后,TOMCAT 不会自动生成名为 JSESSIONID 的 Cookie 。同时,Session 不会将 Cookie 作为识别标志,而是仅仅以重写后的 URL 地址作为识别标志 。

该配置仅禁止 Session 以 Cookie 作为识别标志,无法阻止其他的 Cookie 读写。即服务器不会自动维护名为 JSESSIONID 的 Cookie 了,然而在程序中仍可读写其他的 Cookie 。

Cookie与Session的区别

cookie 数据被存放在客户的浏览器里,而 session 数据则被放在服务器上。

cookie 安全性欠佳,他人能够对存放在本地的 COOKIE 进行分析,并且实施 COOKIE 欺骗行为。鉴于安全方面的考虑,应当使用 session。

session 会在特定的时间内被保存在服务器上。如果访问量增加,就会比较耗费你服务器的性能。鉴于要减轻服务器性能方面的压力,应该使用 COOKIE。

单个 cookie 在客户端存在限制,这个限制是 3K。也就是说,一个站点在客户端所能够存放的 COOKIE 数量不能超过 3K。

Cookie 的方案属于客户端,Session 的方案属于服务端。服务端的 session 实现依赖客户端的 cookie。服务端执行 session 机制时会生成 session 的 id 值,此 id 值会发送给客户端。客户端每次请求都会将该 id 值放到 http 请求头部发送给服务端,且该 id 值在客户端会被保存下来,保存的容器就是 cookie。所以当完全禁掉浏览器的 cookie 时,服务端的 session 就不能正常使用。注意,有些资料称 ASP 可解决此问题,即浏览器的 cookie 被禁掉时,服务端的 session 仍能正常使用,但 ASP 未经过试验。对于网络上很多用 php 和 jsp 编写的网站,发现禁掉 cookie 后,网站的 session 都无法正常访问。

via:

你可能想看:
« 上一篇
下一篇 »

相关推荐

java中什么是冒泡,冒泡算法

2026年09月06日

27阅读

java中冒号,java双冒号

2026年09月06日

26阅读

java中的->,java中的是什么意思

2026年09月06日

24阅读

java中的super用法,Java中super的说明

2026年09月06日

28阅读

java中反射的应用,java中反射的应用场景

2026年09月06日

25阅读

java中开关的定义,Java关键字有哪些

2026年09月06日

25阅读