Session
HTTP 协议是一种无状态协议,即每次服务端接收到客户端的请求时,都是一个全新的请求,服务器并不知道客户端的历史请求记录;Session 和 Cookie 的主要目的就是为了弥补 HTTP 的无状态特性。
大纲
- Session的概念
- Session的创建
- Session的生命周期
- Session的工作机制
- Session的弊端
Session的概念
Session一般译作会话,牛津词典对其的解释是进行某活动连续的一段时间。从不同的层面看待Session,它有着类似但不全然相同的含义。比如,在web应用的用户看来,他打开浏览器访问一个电子商务网站,登录、并完成购物直到关闭浏览器,这是一个会话。而在web应用的开发者开来,用户登录时我需要创建一个数据结构以存储用户的登录信息,这个结构也叫做Session。因此在谈论Session的时候要注意上下文环境。而本文谈论的是一种基于HTTP协议的用以增强web应用能力的机制或者说一种方案,它不是单指某种特定的动态页面技术,而这种能力就是保持状态,也可以称作保持会话
- Session是服务端会话的缓存机制(即记录客户端状态的机制)
- Session是由web的服务器创建,保存在服务端
- Session的存储形式:键值对 >> key = value
- Session的过期时间:默认30 minutes
Session的创建
为了说明问题,这里基于Java Servlet理解Session的创建与原理,这里所说Servlet已经涵盖了JSP技术,因为,Jsp是Servlet技术的反转,开发阶段看到的JSP页面最终也会被编译为Servlet执行,两者有着相同的本质。
在Java中Http的Session对象用javax.servlet.http.HttpSession来表示
一个常见的误解是
:
通常大都以为Session在有客户端访问时就被创建,其实并不是;
所以当用户向服务器发送请求时,Session不一定会被创建起来,而是直到某server端程序调用 HttpServletRequest.getSession(true)
这样的语句时才被创建 。
创建Session的API:二者满足其一即创建Session
/**
* Servlet
* 默认为:true
* 如果把值改为false,则不会创建session >> 即获取到的session值为null
*/
HttpSession session = request.getSession(true);
/**
* JSP
* 默认为:true
* 如果把值改为false,则不会创建session >> 即获取到的session值为null
*/
<%@ page session="true"%>
当用户请求的servlet调用了getSession方法时,都会获取Session,至于是否创建新的Session取决于当前request是否已绑定Session。当客户端在请求中加入了jSessionid标识而servlet容器根据此标识查找到了对应的Session对象时,会将此Session绑定到此次请求的request对象,客户端请求中不带jSessionid或者此jSessionid对应的Session已过期失效时,Session的绑定无法完成,此时必须创建新的Session。同时发送Set-cookie头通知客户端开始保持新的会话
Session的生命周期
1.Session生效
- Session在用户第一次访问服务器时创建。
注意:只有访问JSP、Servlet等程序时才会创建Session,只访问Html,Image等静态资源并不会创建Session,但是可以通过特殊的方式强制生成Session
2.Session失效
- 服务器卸载了当前Web应用,Session销毁;
- 服务器自动清除超过有效期的Session,Session销毁;
服务器会把长时间没有活动的Session从服务器内存中清除,此时的Session便以失效Tomcat中的Session的默认有效期为30分钟
3. 调用Session的invalidate()方法销毁Session;
HttpSession session = request.getSession();
//销毁该request中的所有session
session.invalidate();
//销毁session中指定的属性
session.removeAttribute("key");
3.Session的过期时间计算
- Session的过期时间从Session不活动的时候开始计算,如果session一直活动,session就一直不会过期,也就是说Session只要被访问,Session过期的计时器就会清0
4.Session的有效期设置
- 在web.xml中设置
<!--有效期30分钟 -->
<session-config>
<session-timeout>30</session-timeout>
</session-config>
- 在程序中手动设置
//有效期30分钟(设置单位为秒)
session.setMaxInactiveInterval(30 * 60);
//设置为-1即永不过期
request.getSession().setMaxInactiveInterval(-1);
- 在Tomcat中设置
<!--在Tomcat中的server.xml配置文件中设置-->
<Context path="/livsorder"
docBase="/home/httpd/html/livsorder"
defaultSessionTimeOut="3600" //有效期30分钟
isWARExpanded="true"
isWARValidated="false"
isInvokerEnabled="true"
isWorkDirPersistent="false"/>
Session的工作机制
- 服务器第一次接收到请求,在内存中开辟Session空间,创建session对象,生成sessionId
- 通过响应头Set-cookie:"JSESSIONID=XXXXXXXX"命令,向客户端发送要求设置cookie的响应
- 客户端接收到响应,在浏览器cookie中设置JSESSIONID=XXXXXX信息,接下来的客户端每次向同一个服务发送请求时,该请求都会携带cookie中所包含的JESSIONID=XXXXXX的信息 ,该cookie的过期时间为浏览器回话结束
- 服务器每次接收到请求都会首先从cookie中读取JESSIONID所对应的值,然后通过这个值去session找到该值所对应的用户信息来确认用户身份
Session的弊端
1. Session失效
- Session失效的原因:
上述的Session都是基于cookie,当浏览器禁用了cookie,那么就不会存在cookie,也无法将JESSIONID的信息设置在cookie中,那么session也就失去了应有的作用
- Session失效处理方案:重写URL
具体案例参考:https://www.jianshu.com/p/395bac076ea9
当cookie被禁用之后,就无法继续通过请求头Set-cookie来将JESSIONID设置在cookie中,但是Session的机制只是让客户端每次求同一服务器的时候,携带JESSIONID来实现确认身份作用,而cookie相对来说会让其实现方式更简洁,但是如果cookie不能用,还可以使用其它的方式来实现,<u>最常用的即重写URL,简单的说就是通过URL携带SessionId参数把sessionId传递到客户端,客户端发请求始终携带sessionId即可
//用于对sendRedirect方法后的url地址进行重写
response.encodeRedirectURL(java.lang.String url);
//用于对表单action和超链接的url地址进行重写
response.encodeURL(java.lang.String url);
2. Session Hijack (JESSIONID劫持)
- sessionId被劫持的原因
众所周知cookie是保存在客户端的,也就是说cookie是透明的,那么也就是说cookie中所保存的JESSIONID也是对外可见的,而服务端只认JESSIONID,即只要用户知道JESSIONID的值就可以获取到该JESSIONID所对应的session内容,就会出现安全性的问题,同理重写URL的方式,同样会出现sessionId被劫持可能,这就常说的XSS跨站脚本攻击;
劫持sessionId案例参考:https://www.cnblogs.com/chenpi/p/5434537.html
- session hijack 解决方式
1.加强对提交信息和页面信息的过滤,让非法内容无处施展;
2.设置cookie的httpOnly属性为:true
httpOnly属性值设置为true来避免cookie中内容被(比如JS)恶意脚本读取,这样在1、2双重措施下避免sessionId被劫持(相对来说Set-cookie的方式比URL重写更为安全)
3. Session功能缺陷(重要问题)
- Session资源浪费
因为Session是保存在服务器内存中的,所以随着用户量的大量提升而使Session大量的生成,如果无法及时清理,就会造成Tomcat内存占用过大,导致Tomcat瘫痪
- Session状态的范围局限行
随着业务需求增加,程序的扩展,或者负载均衡,那么程序就会运行在多台无服务器,但是服务器的内存不能在多台服务器之间共享,那么Session也无法共享,就需要面临session同步的问题
- Session功能缺陷的解决方案
无论是资源内存的占用还是Session的共享,其实都可以采用Session持久化解决 ; - 常用的两种持久化解决方案:
<1>.持久化Session到硬盘(FileStore)
<2>.持久化Session到数据库(JDBCStore)通常用Redis数据库