HttpSession(简称session)
session概述
在java web中session是一个存储在WEB服务器端的java对象,该对象代表用户和WEB服务器的一次会话(一次会话指的就是用户在浏览某个网站时,从进入网站到浏览器关闭所经过的这段时间,也就是用户浏览这个网站所花费的时间),通过session对象可以完成数据的存取,而放在session对象中的数据都是用户相关的。也就说张三访问WEB服务器,服务器会生成一个张三的session对象,李四去访问WEB服务器,服务器就会生成一个李四的session对象。 系统为每个访问者都设立一个独立的session对象,用以存取数据,并且各个访问者的session对象互不干扰。 session与cookie是紧密相关的。 session的使用要求用户浏览器必须支持cookie,如果浏览器不支持使用cookie,或者设置为禁用cookie,那么将不能使用Session。除非服务器使用了URL重写机制(uri;jsessionid=xxxxxx)。
思考以下问题
购物网站中的购物车是一个用户一个购物车,购物车是在服务器端的一个java对象,那么该java对象一定是需要找一个临时的区域存储起来的,因为用户在不断的购物,不断的向WEB服务器发送购物请求。那么这个购物车可以存储在ServletContext对象中吗?或者可以存储在HttpServletRequest对象中吗?
1、 购物车是一个用户级别的java对象,不是大家共享的对象,所以购物车千万不能存储在ServletContext对象中。因为ServletContext对象是服务器级别的对象,是大家共享的对象。
2、 购物车是一个用户级别的java对象,用户发送“N次”请求完成购物,这N次请求必须使用底层同一个购物车对象,所以购物车不能存储在HttpServletRequest对象中,如果存储在该对象中,那么用户只要发送一次请求就是一个新的购物车对象。
分析以下案例
假设有两个用户,一个是北京的张三,一个是南京的李四,都在访问京东商城购物网站,那么在京东WEB服务器中一定会有两个购物车,一个是张三的购物车,一个是属于李四的购物车,大家思考:一个WEB服务器,两个浏览器客户端,为什么张三在购物的时候向购物车中放入的商品一定是放到张三的购物车中,而不会存放到李四的购物车中,也就是说session是怎么实现和某个特定用户绑定的?下面使用图形描述session的工作原理:
关于web编程中的Session:
session的工作原理:
当用户第一次访问web服务器的时候,web服务器会为该用户分配一个session对象,并且同时生成一个cookie对象(jsessionid=xxxx),然后web服务器将cookie对象的值和session对象以键值对的方式存储在web服务器端的session列表(Map)中,服务器负责将该cookie数据发送给浏览器,浏览器将cookie信息存储在浏览器的缓存中,只要浏览器不关闭,用户第二次访问服务器的时候会自动发送缓存中存储的cookie数据给服务器,服务器收到cookie数据之后获取cookie的值,然后通过该值在session列表(Map)中搜索对应的session对象。需要注意的是,当浏览器关闭之后,缓存中的cookie消失,这样客户端下次再访问服务器的时候就无法获取到服务器端的session对象了。这就意味着会话已经结束。但是这并不代表服务器端的session对象马上被回收,session对象仍然在session列表中存储,当长时间没有用户再访问这个session对象了,我们称作session超时,此时web服务器才会回收session对象。
Session表示会话,不止是在javaweb中存在,只要是web开发,都有会话这种机制。在java中会话对应的类型是:javax.servlet.http.HttpSession,简称session/会话。Cookie可以将会话状态保存在客户端,HttpSession可以将会话状态保存在服务器端。HttpSession对象是一个会话级别的对象,一次会话对应一个HttpSession对象。
那么什么是一次会话?一般可以这样理解:用户打开浏览器,在浏览器上发送多次请求,直到最终关闭浏览器,表示一次完整的会话。本质上的描述:从session对象的创建,到最终session对象超时之后销毁,这个才是真正意义的一次完整会话。在会话进行过程中,web服务器一直为当前这个用户维护着一个会话对象/HttpSession。在WEB容器中,WEB容器维护了大量的HttpSession对象,换句话说,在WEB容器中应该有一个“session列表”,思考:为什么当前会话中的每一次请求可以获取到属于自己的会话对象? session的实现原理?
- 打开浏览器,在浏览器上发送首次请求。服务器会创建一个HttpSession对象,该对象代表一次会话。
- 同时生成HttpSession对象对应的Cookie对象,并且Cookie对象的name是JSESSIONID(和HttpSession对象关联的这个Cookie的name是比较特殊的,在java中就叫做:jsessionid),Cookie的value是32位长度的字符串,服务器将Cookie的value和HttpSession对象绑定到session列表中,服务器将Cookie完整发送给浏览器客户端,浏览器客户端将Cookie保存到缓存中,只要浏览器不关闭,Cookie不会消失。
- 当再次发送请求的时候,会自动提交缓存当中的Cookie,服务器接收到Cookie,验证该Cookie的name确实是:JSESSIONID,然后获取该Cookie的value。通过Cookie的value去session列表中检索对应的HttpSession对象。
那么浏览器禁用Cookie会出现什么问题?怎么解决?
- 浏览器禁用Cookie,则浏览器缓存中不再保存Cookie,导致在同一个会话中,无法获取到对应的会话对象
- 禁用Cookie之后,每一次获取的会话对象都是新的
- 浏览器禁用Cookie之后,若还想拿到对应的Session对象,必须使用URL重写机制,但是重写URL会给编程带来难度/复杂度,所以一般的web站点是不建议禁用Cookie的。建议浏览器开启Cookie。重写URL:
http://localhost/prj-servlet-21/user/accessMySelfSession;jsessionid=D3E9985BC5FD4BD05018BF2966863E94
浏览器关闭之后,服务器端对应的session对象会被销毁吗?为什么?
浏览器关闭之后,服务器不会销毁session对象,因为B/S架构的系统基于HTTP协议,而HTTP协议是一种无连接/无状态的协议。
什么是无连接/无状态?
请求的瞬间浏览器和服务器之间的通道是打开的,请求响应结束之后,通道关闭,这样做的目的是降低服务器的压力。
什么情况下一次会话结束?
1、 浏览器关闭,缓存中的Cookie消失,会话不一定结束,因为服务器端的session对象还没有被销毁。我们还可以通过URL重写机制继续访问Session对象。
2、 浏览器没关闭,但是由于长时间没有访问web服务器,服务器判定session超时,将session对象销毁。此时浏览器虽然没关闭,但是这次会话已经结束。
3、 session对象所关联的这个Cookie的name有点特殊,这个name必须是jsessionid,必须全部小写,这是HTTP协议中规定的。
4、 浏览器禁用了Cookie,可以采用URL重写机制(这样编码的代价比较大,所以一般网站都是不允许禁用Cookie的)
a) http://ip:port/webapp/servlet/accessSys;jsessionid=xxxxxx
注意:B/S架构采用HTTP协议通信,该协议是一个无连接协议,浏览器向服务器发送请求的瞬间是连接状态,等请求结束之后,B和S的连接断开了,服务器是无法监测浏览器的(浏览器关闭服务器是无法监测的)。
session对象的超时包括三种设置方式
- web系统中引入了session超时的概念。
- 当很长一段时间(这个时间可以配置)没有用户再访问该session对象,此时session对象超时,web服务器自动回收session对象。
- 可配置:web.xml文件中,默认是30分钟
在web.xml中定义:
<session-config>
<session-timeout>30</session-timeout>
</session-config>
HttpSession对象的相关方法
1、获取session对象
(1):request.getSession(true); request.getSession();
- 获取session对象,如果获取不到则新建
(2):request.getSession(false);
- 获取session对象,如果获取不到则返回null
2、向session中存储数据 void setAttribute(String name, Object value)
session.setAttribute("name",ObjectValue);
3、从session中获取数据 Object getAttribute(String name)
Object value = session.getAttribute("name");
4、删除session中某个数据 void removeAttribute(String name)
session.removeAttribute("name");
5、使session失效(销毁session) void invalidate()
session.invalidate();