Session详解
作者:嘭嘭帮
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(见下图)
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("/")
- // 通过 重写URL实现
- response.encodeURL("/");
- response.encodeRedirectURL("/");
- response.sendRedirect(response.encodeRedirectURL("/"));
C、可以在服务器配置,取消重写的功能。配置Tomcat 的<Context disableURLRewriting="true">即可。
3、Session 的 创建
封装在javax.servlet.http.HttpSession 对象中,可以通过request.getSession()获取。
- HttpSession session = request.getSession();//不存在,返回空
- HttpSession session = request.getSession(true);//不存在,新建一个
4、Session 的ID。
- 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);
【输出】
- [JavaWeb] [2014-10-12 11:54:08,345] [DEBUG] [MyFilter:40] - 上下文路径:/JavaWeb
- [JavaWeb] [2014-10-12 11:54:08,345] [DEBUG] [MyFilter:41] - 访问的servlet或者jsp的路径 : /servlet/BaseSession
- [JavaWeb] [2014-10-12 11:54:08,348] [DEBUG] [BaseSession:31] - 请求带过来的session是否有效 : false
- [JavaWeb] [2014-10-12 11:54:08,348] [DEBUG] [BaseSession:35] - request获取的SessionID : 9B582560CB3588E3205030C0B9A9E1D7
- [JavaWeb] [2014-10-12 11:54:08,348] [DEBUG] [BaseSession:39] - 是否是通过Cookie实现: true | 是否是通过URL实现: false
- [JavaWeb] [2014-10-12 11:54:08,361] [DEBUG] [BaseSession:47] - 获取到的Session 为 : org.apache.catalina.session.StandardSessionFacade
- [JavaWeb] [2014-10-12 11:54:08,364] [DEBUG] [BaseSession:51] - 创建的 Session的ID 为 : 95698550D17BB0465D6EC43179A984DB
- [JavaWeb] [2014-10-12 11:54:08,364] [DEBUG] [BaseSession:63] - Session的有效期 为 : 1200
- [JavaWeb] [2014-10-12 11:54:08,364] [DEBUG] [BaseSession:69] - Session创建的时间为 : 2014-10-12 11:54:08
- [JavaWeb] [2014-10-12 11:54:08,365] [DEBUG] [BaseSession:75] - Session最近访问的时间为 : 2014-10-12 11:54:08
- [JavaWeb] [2014-10-12 11:54:08,367] [DEBUG] [BaseSession:85] - Session中放置的数据 : Sam-Sho
- [JavaWeb] [2014-10-12 11:54:08,389] [DEBUG] [BaseSession:96] - request获取的SessionID 2: 9B582560CB3588E3205030C0B9A9E1D7
- [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的方式进行编码;
- 修改前:
- <a href='maillogin.jsp'>
- 修改后:
- <a href="<%=response.encodeURL('maillogin.jsp')%>">