zoukankan      html  css  js  c++  java
  • Session详解

    作者:嘭嘭帮

    作者:邵小宝_1986

    推荐:孤傲苍狼

    Session是服务器端技术,服务器在运行时可以为每个用户的浏览器创建一个其独享的Session对象,由于Session为用户浏览器独享,所以用户在访问服务器的web资源时,可以把各自的资源放在各自的Session中,当用户再去访问服务器中的其他web资源时,其他web资源再从用户各自的Session中取出数据为用户服务。

    一、Session基础知识

    1、工作原理:

    Cookie类似于检查客户身上的“通行证”来确定客户身份的话,那么 Session 机制就是通过检查服务器上的“客户明细表”来确认客户身份。Session相当于程序在服务器上建立的一份客户档案,客户来访的时候只需要查询客户档案表就可以了。

    2、实现方式。

    1)通过 Cookie 实现——将Session的 ID 放入 Cookie。

    A、Session 的实现需要使用Cookie作为识别标志。Session 不能依据 HTTP 连接判断是否为同一个客户,因此服务器向客户端发送一个名为JSESSIONID的 Cookie ,它的值为该Session的ID。Sessin依据该Cookie来识别是否为同一用户。 

    这边的JSESSIONID只是个名字,可以随便修改的。配置服务器的<Context  sessionCookieName=" XXX ">设置。

    B、该Cookie 为服务器自动生成的,它的 maxAge属性一般为 -1,表示仅当前浏览器内有效(包括字窗口),关闭浏览器失效,各浏览器不共享。

    这会是一个问题,当你关闭浏览器,在重开,就会是另一个Cookie。解决办法:服务器在创建Session的时候回写一个同名的Cookie,并设置maxAge值即可,注意有path(见下图)

    // 解决自动生成的cookie为临时性问题,回写一个同名Cookie回去  
    Cookie cookie = new Cookie("JSESSIONID",session.getId());         
    cookie.setMaxAge(session.getMaxInactiveInterval());  
    cookie.setPath(this.getServletContext().getContextPath());  
    response.addCookie(cookie);  

    C、注意:第一次访问的时候,因为JSESSIONID是放在Cookie中,伴随浏览器访问传入,所以第一次访问的时候是没有的。request.getRequestedSessionId() 返回为空。这点在Firefox试验是没问题的。但是Chrome中会有出入。

    Firefox在第一次访问的时候,请求信息中是没有 JSESSIONID数据的,请求结束,服务器返回。如下:

     但是,Chrome在第一次访问的时候,请求中即会有一个临时的JSESSIONID,然后返回一个。如下: 

     问题:

    有一种解释为:第一次访问的时候,在你的程序第一次访问服务器的时候,服务端并不知道你的客户端浏览器是否支持cookie,因此,当你第一次请求发起的时候,服务端会默认url重写,也就是将session id写到url中传递。

    或者只是浏览器的支持问题?暂时没解决。 

    2)通过URL 重写实现——将Session的 ID 重写到URL地址中。

    A、针对客户端不支持Cookie的情况,可以通过 URL 重写实现Session 。

    B、response.encodeURL(String url)实现 URL 地址的重写。如果重定向可以这么写:response.sendRedirect(response.encodeRedirectURL("/")

    1. // 通过 重写URL实现  
    2. response.encodeURL("/");  
    3. response.encodeRedirectURL("/");  
    4. response.sendRedirect(response.encodeRedirectURL("/")); 

    C、可以在服务器配置,取消重写的功能。配置Tomcat 的<Context  disableURLRewriting="true">即可。

    3、Session 的 创建

    封装在javax.servlet.http.HttpSession 对象中,可以通过request.getSession()获取。

    1. HttpSession session = request.getSession();//不存在,返回空  
    2. HttpSession session = request.getSession(true);//不存在,新建一个  

    4、Session 的ID。

    1. String sessionId = session.getId();  

    5、Session 的时间。

    1)有效期。

    // 3-1 有效期  
    // get/set MaxInactiveInterval可以设置和获取session的有效期  单位为 秒  
    // 也可以通过 <session-config>标签配置在web.xml中 ,单位为分钟  
    // tomcat自身的config/web.xml 默认配置session有效期为 30 分钟  
    // 如通过setMaxInactiveInterval设置过有效时间,这段代码注掉,时间还是不会改变。  
      
    session.setMaxInactiveInterval(1000 * 5);  
    int time = session.getMaxInactiveInterval();  

    2)创建时间。

    // 3-2 创建时间  
    long createTime = session.getCreationTime();//返回long  
    Date createDate = new Date(createTime);  
    logger.debug("Session创建的时间为 : " + formatDate(createDate));   

    3)最近访问时间。

    // 3-3 最近访问时间  
    // 客户端只要访问服务器,不管有没有读写session,服务器都会更新最近访问时间,并维护本session  
    long accessedTime = session.getLastAccessedTime();//返回long  
    Date accessedDate = new Date(accessedTime);  
    logger.debug("Session最近访问的时间为 : " + formatDate(accessedDate));  

    6、Session路径

    Session 在客户端对应同一个窗口,没有路径访问问题,同一个servletContext 下的servlet/jsp共享同一个Session 。前提是同一个客户端窗口。 

    二、Session 的生命周期 

    1)Session在用户第一次访问服务器的时候自动创建。只有访问JSP、Servlet等程序才会创建Session(是访问到getSession()代码时), 只访问 HTML、 等静态资源并不会创建Session。 如果尚未生成Session ,也可以使用request.getSession(true)强制生成。

    2)Session生成后,只要用户继续访问,服务器就会更新Session 的最后访问时间,并维护该 Session 。用户每访问服务器一次,无论是否读写 Session ,服务器都认为该用户的 Session “活跃(active)”了一次。

    3)关闭浏览器,不会让 Session 结束,Session 是服务器管理的,只有当 session.invalidate() 代码或者配置好的有效时间<session-comfig>到了,Session 才会结束。

    三、Session的常用方法。

    四、测试代码如下:

    package servlet.session;   
    import java.io.IOException;  
    import java.text.SimpleDateFormat;  
    import java.util.Date;  
    import javax.servlet.ServletException;  
    import javax.servlet.http.HttpServlet;  
    import javax.servlet.http.HttpServletRequest;  
    import javax.servlet.http.HttpServletResponse;  
    import javax.servlet.http.HttpSession;    
    import org.apache.log4j.Logger;  
    /** 
     *  
     * BaseSession.java 
     * 
     * @title Session 
     * @description 
     * @author SAM-SHO  
     * @Date 2014-10-12 
     */  
    public class BaseSession extends HttpServlet {  
        private static final long serialVersionUID = 1L;      
        private Logger logger = Logger.getLogger(this.getClass());    
        public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {  
            this.doPost(request, response);  
        }  
        public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {           
            //    
            boolean isValid = request.isRequestedSessionIdValid();  
            logger.debug("请求带过来的session是否有效 : " + isValid);           
            // 第一次访问的时候 firefox 为空,而chrome 确是有值的,但是和下面创建的session不是同一个  
            String seesionId = request.getRequestedSessionId();  
            logger.debug("request获取的SessionID : " + seesionId);            
            boolean isFromCookie = request.isRequestedSessionIdFromCookie();  
            boolean isFromUrl = request.isRequestedSessionIdFromURL();  
            logger.debug("是否是通过Cookie实现: "  + isFromCookie + " | 是否是通过URL实现: " + isFromUrl);                      
            // 1-Session的创建  
    //      HttpSession session = request.getSession();//不存在,返回空  
            HttpSession session = request.getSession(true);//不存在,新建一个           
            logger.debug("获取到的Session 为 : " + session.getClass().getName());            
            // 2-Session的ID  
            String sessionId = session.getId();  
            logger.debug("创建的 Session的ID 为 : " + sessionId);            
            // 3-session的时间:三个时间构成了session 的生命周期            
            // 3-1 有效期  
            // get/set MaxInactiveInterval可以设置和获取session的有效期  单位为 秒  
            // 也可以通过 <session-config>标签配置在web.xml中 ,单位为分钟  
            // tomcat自身的config/web.xml 默认配置session有效期为 30 分钟  
            // 如通过setMaxInactiveInterval设置过有效时间,这段代码注掉,时间还是不会改变。          
            session.setMaxInactiveInterval(1000 * 5);  
            int time = session.getMaxInactiveInterval();  
            logger.debug("Session的有效期 为 : " + time);                     
            // 3-2 创建时间  
            long createTime = session.getCreationTime();//返回long  
            Date createDate = new Date(createTime);  
            logger.debug("Session创建的时间为 : " + formatDate(createDate));            
            // 3-3 最近访问时间  
            // 客户端只要访问服务器,不管有没有读写session,服务器都会更新最近访问时间,并维护本session  
            long accessedTime = session.getLastAccessedTime();//返回long  
            Date accessedDate = new Date(accessedTime);  
            logger.debug("Session最近访问的时间为 : " + formatDate(accessedDate));                     
            // 4-常用方法           
            // 4-1设置 Attribute 是key-value类型  
            // key为String 类型, value为 Object 。可以放置javaBean。比Cookie强大。            
            session.setAttribute("userName", "Sam-Sho");  
            String userName = (String) session.getAttribute("userName");          
            logger.debug("Session中放置的数据   : " + userName);            
            session.removeAttribute("userName");            
            // 4-2 让session失效  
            session.invalidate();              
            // 4-3 其他与session有关的一些方法          
            String seesionId2 = request.getRequestedSessionId();//  
            logger.debug("request获取的SessionID 2: " + seesionId2);            
            boolean isFromCookie2 = request.isRequestedSessionIdFromCookie();  
            boolean isFromUrl2 = request.isRequestedSessionIdFromURL();  
            logger.debug("是否是通过Cookie实现2: "  + isFromCookie2 + " | 是否是通过URL实现2: " + isFromUrl2);   
    //      // 通过 重写URL实现  
    //      response.encodeURL("/");  
    //      response.encodeRedirectURL("/");  
    //      response.sendRedirect(response.encodeRedirectURL("/"));    
        }        
        /** 
         * 简单转换时间 
         * @param date 
         * @return 
         */  
        private String formatDate(Date date){  
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");  
            String strDate = format.format(date);         
          

    【输出】

     
    1. [JavaWeb] [2014-10-12 11:54:08,345] [DEBUG] [MyFilter:40] - 上下文路径:/JavaWeb  
    2. [JavaWeb] [2014-10-12 11:54:08,345] [DEBUG] [MyFilter:41] - 访问的servlet或者jsp的路径 : /servlet/BaseSession  
    3. [JavaWeb] [2014-10-12 11:54:08,348] [DEBUG] [BaseSession:31] - 请求带过来的session是否有效 : false  
    4. [JavaWeb] [2014-10-12 11:54:08,348] [DEBUG] [BaseSession:35] - request获取的SessionID : 9B582560CB3588E3205030C0B9A9E1D7  
    5. [JavaWeb] [2014-10-12 11:54:08,348] [DEBUG] [BaseSession:39] - 是否是通过Cookie实现: true | 是否是通过URL实现: false  
    6. [JavaWeb] [2014-10-12 11:54:08,361] [DEBUG] [BaseSession:47] - 获取到的Session 为 : org.apache.catalina.session.StandardSessionFacade  
    7. [JavaWeb] [2014-10-12 11:54:08,364] [DEBUG] [BaseSession:51] - 创建的 Session的ID 为 : 95698550D17BB0465D6EC43179A984DB  
    8. [JavaWeb] [2014-10-12 11:54:08,364] [DEBUG] [BaseSession:63] - Session的有效期 为 : 1200  
    9. [JavaWeb] [2014-10-12 11:54:08,364] [DEBUG] [BaseSession:69] - Session创建的时间为 : 2014-10-12 11:54:08  
    10. [JavaWeb] [2014-10-12 11:54:08,365] [DEBUG] [BaseSession:75] - Session最近访问的时间为 : 2014-10-12 11:54:08  
    11. [JavaWeb] [2014-10-12 11:54:08,367] [DEBUG] [BaseSession:85] - Session中放置的数据   : Sam-Sho  
    12. [JavaWeb] [2014-10-12 11:54:08,389] [DEBUG] [BaseSession:96] - request获取的SessionID 2: 9B582560CB3588E3205030C0B9A9E1D7  
    13. [JavaWeb] [2014-10-12 11:54:08,389] [DEBUG] [BaseSession:100] - 是否是通过Cookie实现2: true | 是否是通过URL实现2: false  

    五、Session 和 Cookie 的比较。

    1、从存取方式上比较:

    1)Cookie 中只能存ASCII字符串,其他需要编码。不能直接存 java 对象。

    2)Session 中可以存取任何类型的数据,直接保存JavaBean。

    2、从隐私安全上比较

    1)Cookie存储在客户端,会存在风险。所以一般一些敏感信息,如密码等尽量不要放入 Cookie,并且对Cookie 信息加密。提交到服务器在解密,保证安全性。

    2)Session 存储在服务器,安全多了。

    3、从有效期上比较

    1)Cookie 的有效期只要设置Cookie 的maxAge即可。

    2)Session 如果设置的有效期过长,会导致服务器累计的 Session 过多,导致内存溢出。

    4、从对服务器负担上比较

    1)Cookie无负担,所以比如大型的网站,电商等都会使用Cookie 追踪客户会话。

    2)Session 过多就会影响服务器了。

    一、客户端用cookie保存了sessionID

    客户端用cookie保存了sessionID,当我们请求服务器的时候,会把这个sessionID一起发给服务器,服务器会到内存中搜索对应的sessionID,如果找到了对应的 sessionID,说明我们处于登录状态,有相应的权限;如果没有找到对应的sessionID,这说明:要么是我们把浏览器关掉了(后面会说明为什 么),要么session超时了(没有请求服务器超过20分钟),session被服务器清除了,则服务器会给你分配一个新的sessionID。你得重 新登录并把这个新的sessionID保存在cookie中。 

    在没有把浏览器关掉的时候(这个时候假如已经把sessionID保存在cookie中了)这个sessionID会一直保存在浏览器中,每次请求的时候都会把这个sessionID提交到服务器,所以服务器认为我们是登录的;当然,如果太长时间没有请求服务器,服务器会认为我们已经所以把浏览器关掉了,这个时候服务器会把该sessionID从内存中清除掉,这个时候如果我们再去请求服务器,sessionID已经不存在了,所以服务器并没有在内存中找到对应的 sessionID,所以会再产生一个新的sessionID,这个时候一般我们又要再登录一次。 

    二、客户端没有用cookie保存sessionID

    这 个时候如果我们请求服务器,因为没有提交sessionID上来,服务器会认为你是一个全新的请求,服务器会给你分配一个新的sessionID,这就是 为什么我们每次打开一个新的浏览器的时候(无论之前我们有没有登录过)都会产生一个新的sessionID(或者是会让我们重新登录)。 

    当我们一旦把浏览器关掉后,再打开浏览器再请求该页面,它会让我们登录,这是为什么?我们明明已经登录了,而且还没有超时,sessionID肯定还在服 务器上的,为什么现在我们又要再一次登录呢?这是因为我们关掉浏览再请求的时候,我们提交的信息没有把刚才的sessionID一起提交到服务器,所以服 务器不知道我们是同一个人,所以这时服务器又为我们分配一个新的sessionID,打个比方:浏览器就好像一个要去银行开户的人,而服务器就好比银行, 这个要去银行开户的人这个时候显然没有帐号(sessionID),所以到银行后,银行工作人员问有没有帐号,他说没有,这个时候银行就会为他开通一个帐 号。所以可以这么说,每次打开一个新的浏览器去请求的一个页面的时候,服务器都会认为,这是一个新的请求,他为你分配一个新的sessionID。

     用户浏览器禁用了cookie,SessionID如何传递

    HttpServletResponse.encodeURL( url)重写URl,对给定的url,通过加上session ID的方式进行编码;

    1. 修改前:   
    2.         <a href='maillogin.jsp'>   
    3. 修改后:   
    4.         <a href="<%=response.encodeURL('maillogin.jsp')%>">  
  • 相关阅读:
    SQL SERVER 运维日记
    openstack
    Java GC 日志详解
    突破 BTrace 安全限制
    End-to-End Tracing of Ajax/Java Applications Using DTrace
    调试工具BTrace 的使用--例子
    btrace-dtrace-for-java-ish
    DTrace Probes in HotSpot VM
    DTrace memory leak 内存泄露
    Java-JVM-GC
  • 原文地址:https://www.cnblogs.com/lxl57610/p/7477325.html
Copyright © 2011-2022 走看看