赞
踩
HTTP协议为无状态协议,对于每一个web请求,服务器是无法知道是否为同一个请求者。那么是怎么样跟踪请求的呢?
目前有两种方式。
第一种,使用cookie记录标志。浏览器是可以保存cookie信息的,在请求响应的时候,创建一个对应的cookie,记录一个编号,下次再发送请求的时候,将cookie记录的信息发送到服务器上,服务器取得这个值,就可以判断是否为同一个用户发送的请求了。
第二种,使用URL重写。每次URL后面跟随一个参数,服务器取得这个参数,也可以判断是否为同一个用户的请求。
index.html; jsessionid=1234
对应用服务器来说,会先检查浏览器是否支持cookie,如果支持就采用cookie,如果不支持则自动采用URL重写,这个过程是由Servlet规范规定的,所有的Servlet容器都需要实现这样的功能,不需要人为干预。
当然,如果服务器一直保存session信息,用户关闭了浏览器,或者离开了网站,session信息就没有必要保存在服务器上了。怎么清理呢?
Session的超时机制就是来处理这种情况的,如果在规定的时间内,第一次请求时,服务器创建新的session,并且会记录时间,如果很长时间没有信息相同的session id信息过来,服务器会人为用户没有使用了,就自动清理掉这个对应的这个session了。
参考web.xml的配置sessiontimeout项。
这个作用域是最严格的,此对象只对于它所在JSP页面是可访问的。
这个作用域的对象是在相应请求的生命周期内有效。也就是说,对象在创建它的页面内有效,以及请求被转发(forward方法)或者被包含(include方法)的页面内有效。
会话域的对象,对于参与某个客户端会话周期的所有请求,数据都是一致的。如果有多个请求操作session,可能会有多线程的问题。
比如先发送A请求,立即发送B请求:
A请求访问session,设置某一个属性的值为a。
B请求读取session,读取A设置的属性值。
如果在A响应之前B请求已经发出去了,B读取的时候A还没有设置,B读取到的值就不是a了。
这是最宽泛的作用域,application里的变量可以被所有用户共享,类似全局变量。这类对象不是线程安全的,如果多个请求试图同时修改某一个对象,那么必须对这些访问进行同步处理。
如果用户甲的操作修改了application中的变量,用户乙访问时得到的是修改后的值。这在其他 scope中都是不会发生的,page, request, session都是完全隔离的,无论如何修改都不会影响其他人的数据。
Servlet API只是定义了一组接口和一些实现类,HttpSession就是一个接口,具体的实现类不同的servlet容器有不同的实现。
比如weblogic8里面使用的是HashTable来保存session的属性和值,而tomcat6里面则是使用ConcurrentHashMap来保存。
HttpSession常用方法:
getAttribute(java.lang.String name) | 返回session中绑定的变量名的值,如果没有则返回null |
getId() | 返回jsessionId的值 |
invalidate() | 取消当前会话,系统退出之前调用 |
removeAttribute(java.lang.String name) | 删掉session某绑定的变量 |
setAttribute(java.lang.String name, java.lang.Object value) | 添加对于的名称和值到session中 |
1. 保存用户特定数据,比如用户角色,操作集合等
2. 多个不同请求之间的共享数据
1. 对所有用户都可以共享的数据,比如机构列表缓存,系统某功能的配置基表等
2. 数据提交前的临时存放,可能存在数据覆盖的情况,使用request转发或使用隐藏表单
新窗口打开方式
IE6
IE8
CTRL+N
共享session
共享session
winodw.open
共享session
共享session
链接
共享session
共享session
打开IE
新建session
共享session
创建标签页
无
共享session
对于同一用户从同一系统中同时打开多个相同的页面,此时浏览器会共享session,如果这个页面操作,服务器上有更新session对象的信息,可能会导致session信息会被覆盖。
举例:
打开页面page.jsp后,输入信息,然后提交,提交时从session取key的值。
假设某页面page.jsp每次打开之后,都会根据数据设置session。
第一次的数据值为value1:
session.setAttribute("key","value1");
第二次的数据值为value2:
session.setAttribute("key","value2");
同时打开两个page.jsp,第一次打开之后未提交,第二次打开之后也未提交。
此时,如果回到第一个页面,并提交,取到的key值是value2,数据有异常。
回到第二个页面,并提交,取到的key值是value2,数据正常。
规避措施:
a. 禁止同一页面同时打开多次
b. a条件不满足的情况下,不使用session保存数据,考虑使用页面表单的hidden域传值,或者使用request请求转发
c. 对于GET请求,可以使用URL重写,加入参数,敏感信息需要加密不能使用
有时候为了增加客户体验,需要在后面的页面中保留上一个页面输入的内容,例如分页显示列表,这个时候有两种做法可以选择。
A. 使用页面表单隐藏数据。将计算得到总条数,总页数,每页的数量,当前页数,开始的索引等数据放到页面表单中,当选择下一页或者上一页时,每次都将这些数据传到后台进行处理。
B. 使用session缓存。将计算得到总条数,总页数,每页的数量,当前页数,开始的索引等数据组装成分页对象放到session中,当选择下一页或者上一页时,后台从session中获取数据,再进行处理。
对于同一客户不同产品进行的受理,存在session数据覆盖的情况,此时就要特别注意了。如果改造成页面隐藏字段的方式确实很困难,在使用session的时候,可以对不同的产品进行拆分,使用跟产品相关的session key值,比如,可以使用保单号作为session的key,而不是使用保单对象。
代码示例:
PolicyDTO policy=new PolicyDTO ();
session.setAttribute(“policyDTO”,policy);//会产生数据覆盖问题
session.setAttribute(policyDTO.getPolicyNo,policy);//不会产生数据覆盖问题
在服务退出或者受理提交之后,需要清理掉session中的数据,否则会造成垃圾数据过多,服务器内存泄露。
在IE6中,不同方式会有不同的行为,在IE8中,不同窗口共享一个会话。如果要使IE8和IE6在打开IE时,表现一致,在IE8启动参数中加入-nomerge。
对于多个不同请求之间共享的数据,如果放在session中,可能存在并发的问题。
请求响应的时间,由于网络,服务器等因素可能慢,也可能快,如果先后发送两个请求到服务器,可能后发送的请求会先响应,这时取到的值就不是期望的了。
示意图如下,和图三是有区别的,2A表示先于写之前取值,2B表示正常的情况。
对于这样的情况,可以使用顺序操作,设置session之后,跳转到一个新的页面,在新的页面上在去读session里面的数据。见示意图五。
在IE中使用showModalDialog方法打开一个新的窗口的时候,会创建一个新的窗口实例。如果这个实例是在新的进程中打开的,所有的cookies和session id都不能使用了,这个实例和winodw.open方法打开的实例是不一样的,也就是说showModalDialog在新进程中打开的窗口,和父窗口不共享session,这里使用的时候需要特别注意。
关于showModalDialog方法的详细描述,请参考链接文档:
在msdn上搜索 showModalDialog method
此处无法提供链接
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。