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')%>">  
posted @ 2017-09-05 10:27  李慕白520  阅读(289)  评论(0编辑  收藏  举报