Javaweb Session机制
一、前言
session,中文经常翻译为会话,其本来的含义是指有始有终的一系列动作/消息,比如打电话是从拿起电话拨号到挂断电话这中间的一系列过程可以称之为一个session。
session在Web开发环境下的语义又有了新的扩展,它的含义是指一类用来在客户端与服务器端之间保持状态的解决方案。有时候Session也用来指这种解决方案的存储结构。
二、Session机制
session机制采用的是在服务器端保持 HTTP 状态信息的方案 。
服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。
当程序需要为某个客户端的请求创建一个session时,服务器首先检查这个客户端的请求里是否包含了一个session标识(即sessionId),如果已经包含一个sessionId则说明以前已经为此客户创建过session,服务器就按照session id把这个session检索出来使用(如果检索不到,可能会新建一个,这种情况可能出现在服务端已经删除了该用户对应的session对象,但用户人为地在请求的URL后面附加上一个JSESSION的参数)。如果客户请求不包含sessionId,则为此客户创建一个session并且生成一个与此session相关联的sessionId,这个session id将在本次响应中返回给客户端保存。
三、保存Session id的几种方式
保存session id的方式可以采用cookie,这样在交互过程中浏览器可以自动的按照规则把这个标识发送给服务器。
由于cookie可以被人为的禁用,必须有其它的机制以便在cookie被禁用时仍然能够把session id传递回服务器,经常采用的一种技术叫做URL重写,就是把session id附加在URL路径的后面,附加的方式也有两种,一种是作为URL路径的附加信息,另一种是作为查询字符串附加在URL后面。网络在整个交互过程中始终保持状态,就必须在每个客户端可能请求的路径后面都包含这个session id。
四、Session Cookie
session通过SessionID来区分不同的客户, session是以cookie或URL重写为基础的,默认使用cookie来实现,系统会创造一个名为JSESSIONID的输出cookie,这称之为session cookie,以区别persistent cookies(也就是我们通常所说的cookie),session cookie是存储于浏览器内存中的,并不是写到硬盘上的,通常看不到JSESSIONID,但是当把浏览器的cookie禁止后,web服务器会采用URL重写的方式传递Sessionid,这时地址栏会看到
session cookie针对某一次会话而言,会话结束session cookie也就随着消失了,而persistent cookie只是存在于客户端硬盘上的一段文本。
关闭浏览器,只会是浏览器端内存里的session cookie消失,但不会使保存在服务器端的session对象消失,同样也不会使已经保存到硬盘上的持久化cookie消失。
五、Session的创建与删除
一个常见的错误是以为session在有客户端访问时就被创建,然而事实是直到某server端程序(如Servlet)调用HttpServletRequest.getSession(true) 或者 HttpServletRequest.getSession()这样的语句时才会被创建。
session在下列情况下被删除:
A.程序调用HttpSession.invalidate()
B.距离上一次收到客户端发送的session id时间间隔超过了session的最大有效时间
C.服务器进程被停止
注意:关闭浏览器只会使存储在客户端浏览器内存中的session cookie失效,不会使服务器端的session对象失效。
另外,两个浏览器窗口访问应用程序会使用同一个session
通常session cookie是不能跨窗口使用的(IE 8 版本以前),当你新开了一个浏览器窗口进入相同页面时,系统会赋予你一个新的session id,这样信息共享的目的就达不到了。
此时可以先把session id保存在persistent cookie中(通过设置cookie的最大有效时间),然后在新窗口中读出来,就可以得到上一个窗口的session id了,这样通过session cookie和persistent cookie的结合就可以实现了跨窗口的会话跟踪。
六、Session的超时管理
WEB服务器无法判断当前的客户端浏览器是否还会继续访问,也无法检测客户端浏览器是否关闭,所以,即使客户已经离开或关闭了浏览器,WEB服务器还要保留与之对应的HttpSession对象。
随着时间的推移而不断增加新的访问客户端,WEB服务器内存中将会因此积累起大量的不再被使用的HttpSession对象,并将最终导致服务器内存耗尽。
WEB服务器采用“超时限制”的办法来判断客户端是否还在继续访问,如果某个客户端在一定的时间之内没有发出后续请求,WEB服务器则认为客户端已经停止了活动,结束与该客户端的会话并将与之对应的HttpSession对象变成垃圾。
如果客户端浏览器超时后再次发出访问请求,WEB服务器则认为这是一个新的会话的开始,将为之创建新的HttpSession对象和分配新的会话标识号。
会话的超时间隔可以在web.xml文件中设置,其默认值由Servlet容器定义。
<session-config>
<session-timeout>30</session-timeout>
</session-config>
七、Java中与Session相关的常用方法
HttpSession接口中的方法
getId方法
getCreationTime方法
getLastAccessedTime方法
setMaxInactiveInterval方法
getMaxInactiveInterval方法
isNew方法:如果客户端请求消息中返回了一个与Servlet程序当前获得的HttpSession对象的会话标识号相同的会话标识号,则认为这个HttpSession对象不是新建的。
invalidate方法
getServletContext方法
setAttribute方法
getAttribute方法
removeAttribute方法
getAttributeNames方法
HttpServletRequest接口中的Session方法
getSession方法
public HttpSession getSession(boolean create)
public HttpSession getSession()
isRequestedSessionIdValid方法
isRequestedSessionIdFromCookie方法
isRequestedSessionIdFromURL方法
八、利用URL重写实现Session跟踪
Servlet规范中引入了一种补充的会话管理机制,它允许不支持Cookie的浏览器也可以与WEB服务器保持连续的会话。这种补充机制要求在响应消息的实体内容中必须包含下一次请求的超链接,并将会话标识号作为超链接的URL地址的一个特殊参数。
将会话标识号以参数形式附加在超链接的URL地址后面的技术称为URL重写。如果在浏览器不支持Cookie或者关闭了Cookie功能的情况下,WEB服务器还要能够与浏览器实现有状态的会话,就必须对所有可能被客户端访问的请求路径(包括超链接、form表单的action属性设置和重定向的URL)进行URL重写。
HttpServletResponse接口中定义了两个用于完成URL重写方法:
encodeURL方法
encodeRedirectURL方法
九、application与session辨析
application域范围属性
Session域范围属性
十、HttpSession 的生命周期:
什么时候创建 HttpSession 对象?
是否浏览器访问服务端的任何一个JSP或Servlet,服务器都会立即创建一个 HttpSession 对象呢?不一定。若当前的JSP(或Servlet)是客户端访问的当前WEB应用的第一个资源,且JSP的page指定的session属性值为false, 则服务器就不会为JSP创建一个HttpSession对象;若当前 JSP 不是客户端访问的当前 WEB 应用的第一个资源,且其他页面已经创建一个 HttpSession 对象,则当前 JSP 页面会返回一个会话的 HttpSession 对象,而不会创建一个新的 HttpSession‘ 对象
session=“false“ 到底表示什么意思?当前 JSP 页面禁用 session 隐含变量!但可以使用其他的显式的 HttpSession 对象
对于 Serlvet 而言:若 Serlvet 是客户端访问的第一个 WEB 应用的资源,则只有调用了 request.getSession() 或 request.getSession(true) 才会创建 HttpSession 对象
什么时候销毁 HttpSession 对象?
有待补充.............
十一、利用Session避免表单的重复提交
调用 RequestDispatcher.forward() 方法,浏览器所保留的URL 是先前的表单提交的 URL,此时点击”刷新”, 浏览器将再次提交用户先前输入的数据,引起重复提交
如果采用 HttpServletResponse.sendRedirct() 方法将客户端重定向到成功页面,将不会出现重复提交的问题
包含有FORM表单的页面必须通过一个服务器程序动态产生,服务器程序为每次产生的页面中的FORM表单都分配一个唯一的随机标识号,并在FORM表单的一个隐藏字段中设置这个标识号,同时在当前用户的Session域中保存这个标识号。
当用户提交FORM表单时,负责接收这一请求的服务器程序比较FORM表单隐藏字段中的标识号与存储在当前用户的Session域中的标识号是否相同,如果相同则处理表单数据,处理完后清除当前用户的Session域中存储的标识号。在下列情况下,服务器程序将忽略提交的表单请求:
①当前用户的Session中不存在表单标识号
②用户提交的表单数据中没有标识号字段
③存储在当前用户的Session域中的表单标识号与表单数据中的标识号不同
浏览器只有重新向WEB服务器请求包含FORM表单的页面时,服务器程序才又产生另外一个随机标识号,并将这个标识号保存在Session域中和作为新返回的FORM表单中的隐藏字段值。
TokenProcessor.java:用于管理表单标识号的工具类,它主要用于产生、比较和清除存储在当前用户Session中的表单标识号。为了保证表单标识号的唯一性,每次将当前SessionID和系统时间的组合值按MD5算法计算的结果作为表单标识号,并且将TokenProcessor类设计为单件类
表单提交常见问题:同一个用户打开同一个浏览器进程的多个窗口来并发访问同一个WEB站点的多个FORM表单页面时,将会出现表单无法正常提交的情况。
解决方案:将FORM表单的标识号作为表单隐藏字段的名称,如下所示:
<input type='hidden' name='4b15c6b2f573831b4b5107d849fcafb8' value=''>
将所有的表单标识号存储进一个Vector集合对象中,并将Vector集合对象存储进Session域中。当表单提交时,先从Session域中取出Vector集合对象,然后再从Vector集合对象中逐一取出每个表单标识号作为参数调用HttpServletRequest.getParameter方法,如果其中有一次调用的返回值不为null,则接受并处理该表单数据,处理完后将该表单标识号从Vector集合对象中删除。
十二、利用Session实现一次性验证码
一次性验证码的主要目的就是为了限制人们利用工具软件来暴力猜测密码,其原理与利用Session防止表单重复提交的原理基本一样,只是将表单标识号变成了验证码的形式,并且要求用户将提示的验证码手工填写进一个表单字段中,而不是通过表单的隐藏字段自动回传给服务器。
服务器程序接收到表单数据后,首先判断用户是否填写了正确的验证码,只有该验证码与服务器端保存的验证码匹配时,服务器程序才开始正常的表单处理流程。
密码猜测工具要逐一尝试每个密码的前题条件是先输入正确的验证码,而验证码是一次性有效的,这样基本上就阻断了密码猜测工具的自动地处理过程。
如果,您对我的这篇博文有什么疑问,欢迎评论区留言,大家互相讨论学习。
如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】。
如果,您希望更容易地发现我的新博客,不妨点击一下左下角的【关注我】。
如果,您对我的博文感兴趣,可以关注我的后续博客,我是【AlbertRui】。转载请注明出处和链接地址,欢迎转载,谢谢!