Session机制分析

Session工作原理

创建Session一个常见的误解是以为session在有客户端访问时就被创建,然而事实是直到某server端程序调用HttpServletRequest.getSession(true)这样的语句时才被创建。如果JSP没有显示的使用 <%@page session="false"%> 关闭session,则JSP文件在编译成Servlet时将会自动加上这样一条语句HttpSession session = HttpServletRequest.getSession(true);这也是JSP中隐含的session对象的来历。 由于session会消耗内存资源,因此,如果不打算使用session,应该在所有的JSP中关闭它。
在服务器系统中会为每一个会话(浏览器)维护一个Session。不同的会话,对应不同的Session,那么系统是如何识别各个Session对象的?即如何在一个会话过程中,一直使用一个Session对象。
有四个步骤:

  1. 写入Session列表
  2. 服务器生成并发送Cookie
  3. 客户端接收并发送Cookie
  4. 从Session列表中查找

写入Session列表

服务器当前应用的Session是以Map管理的,这个Map称为Session列表。该Map的Key为一个长度为32位长度的随机串,这个随机串为JSESSIONID,Value则为HttpSession对象的引用

KeyValue
Q12GH6YUIO8764BDK84NZUI3NR67S5S6HttpSession的引用1
1B4HDI387DYEN7XIW72MLZ72NE7AB3E4HttpSession的引用2

当用户第一次提交请求时,服务端Servlet执行到request.getSession()方法后,会自动生成一个Map.Entry对象,Key为JSESSIONID,Value为新创建HttpSession对象

服务器生成并发送Cookie

在再将Session信息写入Session 列表后,系统还会将“JSESSIONID”作为name,“32位长度的随机串”作为value,以Cookie的形式存放到响应报头中,并随着响应将此Cookie发送到客户端。对于这个响应报头实现的前提是你调用getSession方法在这里插入图片描述

客户端接收并发送Cookie

客户端接收到这个Cookie后会将其存放到浏览器的缓存中,即只要客户端浏览器不关闭,浏览器缓存中Cookie就不会消失
在这里插入图片描述

当用户提交第二次请求时,会将这个缓存中的Cookie,伴随着请求的头部信息,一块发送到服务端

从Session列表中查找

服务端从请求读取到客户端发送来的Cookie,并根据Cookie中JSESSIONID的值,从Map中查找相应的Key对应的Value,即Session对象。然后对该Session对象的域属性进行读写操作。

Session的失效

session失效后,但失效的Session并不为null
下面是官方API文档解释

invalidate()
Invalidates this session then unbinds any objects bound to it.

还有一个使Session失效的方法是removeAttribute()方法

Session与Cookies的关系

在应用中,通过Session的工作原理,服务器之所以可以针对不同的会话找到不同的Session,是因为Cookie完成了会话的跟踪。但是,若客户端禁用Cookies后,服务器就无法维持同一个Session,因为无法从客户端获取并向服务端发送JSESSIONID。这是服务器就会认为是新的Session,就会有创建新的JSESSIONID。

解决Cookies失效

Session依赖于Cookies存在
在解决这个问题之前,要明确Session和Cookies分别在客户端和服务端都有存在!
默认情况下,当getSession()后,session就被被创建。session在创建时,服务器会通过Cookie返回session 的ID给浏览器,之后服务器根据浏览器Cookie里的session的ID来分辨不同用户。但是,这种方法返回的cookie是保存在浏览器的内存中,浏览器关闭后内存会被清理,所以在session在关闭浏览器后就失效了。虽然在服务器保存的session会在在有效期后才会被销毁,但是用户的cookie里没有session的ID,服务器就不能判断出当前用户是否是原先的那个用户。

解决方法:
我们可以创建一个新的CooKie,该Cookie的名字为JSESSIOID,path为WEB应用的虚拟路径,并设置setMaxAge()的毫秒值,让Cookie保存在客户端的硬盘中,这时即使多次对浏览器进行关开操作是不会清楚客户端硬盘文件的。所以,Cookie就不丢失了,SessionId也不会随浏览器关闭而丢失。

Cookie cookie = new Cookie("JSESSIONID",session.getId());
cookie.setPath(request.getContextPath()+"/");
cookie.setMaxAge(30*60);
response.addCookie(cookie);

解决客户端Session被禁用

修改地址栏

由于cookie可以被人为的禁止,必须有其他机制以便在cookie被禁止时仍然能够把session id传递回服务器。经常被使用的一种技术叫做URL重写,就是把session id直接附加在URL路径的后面,附加方式也有两种,一种是作为URL路径的附加信息,表现形式为https://localhost/资源路径;jsessionid=32位字符串
另一种是作为查询字符串附加在URL后面,表现形式为https://localhost/资源路径?jsessionid=32位字符串
这两种方式对于用户来说是没有区别的,只是服务器在解析的时候处理的方式不同,采用第一种方式也有利于把session id的信息和正常程序参数区分开来。 为了在整个交互过程中始终保持状态,就必须在每个客户端可能请求的路径后面都包含这个session id。

对URL重写

重定向Session跟踪

调用encodeRedirectURL()方法重写URL

String uri = request.getContextPath()+"/otherServlet";
uri = response.encodeRedirectURL(uri);
response.sendRedirect(uri);
非重定向Session跟踪

在超链接转发的时候禁用,禁用Cookies,SomeServlet向客户端发送来Cookie,客户端不可以存储到本地,当超链接到OtherServlet的时候,即使是同一个会话,也不可以访问Session的域内容。这里可以使用encodeURL()方法对URL进行重写

response.setContentType("text/html;charset=utf-8");
PrintWrite out = response.getWrite();
String uri = "otherServlet";
uri = response.encodeURL(uri);
out.print("<a href = '" + uri +"'>跳转</a>到OtherServlet");
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值