一:现象
有小伙伴写了下面一段代码,然后发现,随着每次关闭浏览器,count的值重新开始计数了,如下:
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {HttpSession session = request.getSession();
if (session.getAttribute("b") == null) {
session.setAttribute("b", 1);
} else {
int count = (Integer) session.getAttribute("b");
session.setAttribute("b", count + 1);
}
System.out.println((Integer) session.getAttribute("b"));
}
同学心中有疑虑,不是说session有默认失效时间30分钟吗,怎么我的session随着浏览器关闭瞬间失效了?
二:原因
我们是在浏览器中通过url去访问web服务器的。当我们访问浏览器的时候,就得告诉web服务器,你就是你。比如,张三在北京打开浏览器,访问zuikc.com/hello,李四在上海打开浏览器,同样访问zuikc.com/hello。那服务器得知道这两个请求,一个是张三的,一个是李四的。
服务器怎么判断?这需要浏览器配合。
浏览器访问服务器的时候,会带上一个sessionid,比如上文代码中,我们在chrome中可以看到这个sessionid,
张三和李四的sessionid是不同,对于服务器来说,就知道是两个不同的人访问了我,这样它才能在自己的内存中维护一个session的字典,这个字典集合的key就是这个sessionid,这样才能保持两个人之间的session的值是相互独立的。比如,张三的b值+1了,而李四的b值是不会加1的。
but,注意到上图红圈中的session(此session非彼session,不是上文中所指的服务器端session,如果是我,一定会给它改个名,叫做“temp临时”)了吗?
【重点】
1:sessionid一般是存储在浏览器cookie中的;
2:而cookie分为临时(session)cookie和永久cookie。上图中带session字样的就是临时cookie,带有日期的就是永久cookie;
3:临时cookie存储在浏览器内存中,随着浏览器关闭而没有了;
4:永久cookie存储在硬盘上,在日期前都会存在;
所以,很不幸,我们的sessionid是个临时cookie,我们关闭浏览器,它就没有了,不信?大家可以尝试关闭再打开浏览器,看看sessionid的值是不是变化了。
三:解决办法
道理很简单,原因也找到了,要解决这个问题就稍微有点复杂了。我们得拦截sessionid写到cookie的这个过程,将它变为一个永久cookie,或者,咱就不要将sessionid存在cookie了,存储在数据库、分布式缓存或者别的什么地方。现在,我们来写一个大致思路:
1:封装自定义的HttpServletRequest;
2:封装自定义的 HttpSession
3:定义一个filter,拦截HttpServletRequest对象,在dofilter的时候,将sessionid得到,在写cookie的时候将sessionid变为一个永久cookie;
四:关于session还有很多好玩的东西
比如,重新在服务器端生成自己的session值,如下:
HttpSession oldSession = request.getSession(); Enumeration attrNames = oldSession.getAttributeNames(); Properties props = new Properties(); if (attrNames != null) { while (attrNames.hasMoreElements()) { String key = (String) attrNames.nextElement(); props.put(key, oldSession.getAttribute(key)); } //Invalidating previous session oldSession.invalidate(); //Generate new session HttpSession newSession = request.getSession(true); attrNames = props.keys(); while (attrNames.hasMoreElements()) { String key = (String) attrNames.nextElement(); newSession.setAttribute(key, props.get(key)); } }