Java Servlet 规范 第7章 会话

来源:互联网 发布:阿里云 服务器 翻墙 编辑:程序博客网 时间:2024/06/04 19:51

第七章

Sessions(会话)


超文本传输协议(HTTP)被设计为无状态协议。为了建立起有效的Web应用,把来自同一个用户的多次请求联系起来就很重要了。随着时间的流逝,出现了很多会话跟踪技术,但这些技术让程序员直接应用都很麻烦。


7.1 会话跟踪机制

下面的部分描述如何跟踪一个用户的会话。

7.1.1 Cookies

通过HTTP cookies跟踪会话是用的最多的会话跟踪机制,并且所有的servlet容器都应该支持。

容器发送一个cookie给客户。这个客户在以后每次请求时都会带上这个cookie,这样就明确的将请求和会话联系起来了。会话跟踪cookie的标准的名字必须是JSSSIONID。通过容器具体的配置,可能会允许用户自定义会话跟踪cookie的名字。

所有的servlet容器必须提供配置session是否是HttpOnly的能力。已经建立的配置必须应用到所有还没有配置的上下文中(想了解更多细节,请查看java文档中的SessionCookieConfig)。

如果一个web应用配置了一个用户自定义的会话跟踪cookie名字,并且会话id被编码进了URL,那么这个URI参数也要用相同的名字(假如启用了URL重写)。

7.1.2 SSL Sessions

安全套接字层(Secure Sockets Layer),在HTTPS协议中应用的加密技术,有一个内部的机制允许从一个客户发出的多个请求能够被唯一的识别到一个会话中。一个servlet容器能够很容易地用这个数据定义一个会话。

7.1.3 URL 重写

URL重写是会话跟踪方法中最底层的其他方法都用的方法。当一个客户不能接受cookie时,URL重写就可能是服务器能用的基本的会话跟踪方法了。URL重写包括添加数据和一个session ID到URL路径上,根据这些数据容器就能够把一个请求和一个会话联系起来。

session ID必须被编码后作为URL路径的参数。参数的名称必须是jsessionid。下面是一个包含被编码信息的URL路径的例子:

http://www.myserver.com/catalog/index.html;jsessionid=1234

URL重新会把会话标识暴露给日志,书签,referer headers,HTML缓存和URL工具条。当cookies和SSL sessions可用时,不应该用URL重写。

7.1.4 会话完整性

就算客户端不支持cookies,Web容器也必须支持HTTP会话。为了满足这个需求,Web容器一般会支持URL重写机制。


7.2 创建一个会话

一个会话是“新的”,当它仅是一个未来的并且还没有被建立起来的会话。因为HTTP是基于请求-响应的协议,一个HTTP会话是新的直到一个客户“加入”它。当会话跟踪信息返回给服务端时才表明客户加入一个会话,这时会话才被建立。除非客户加入一个会话,否则从客户发来的下一个请求不能被认为是会话的一部分。

下面的任一条件满足就认为会话是“新的”:

  • 客户端还不知道会话
  • 客户端选择不加入会话

一个Servlet的开发者必须在它的应用程序中处理客户还没加入,不能加入或不想加入一个会话的情况。

每一个会话都跟一个session id相关联。session id 的值可以通过调用javax.servlet.http.HttpSession.getId() 得到,在得到后也可以通过javax.servlet.http.HttpServletRequest.changeSessionId() 改变。


7.3 Session 范围

HttpSession对象必须被限定在application(或Servlet context)范围级别。底层的机制,比如用于建立会话的cookie,在不同的上下文中可以相同,但是引用的对象,包括对象的属性,必须不能再容器的不同上下文中共享。

用一个例子演示这个需求:如果一个servlet用RequestDispatcher 调用另一个Web应用中的一个servlet,被调用的servlet中的任何session必须和调用的servlet中的不同。

另外,上下文中的会话必须能够被恢复不论相关的上下文是被直接访问还是作为转发的目标。


7.4 在Session中绑定属性

一个servlet可以通过名字绑定一个对象属性到一个HttpSession的实现。任何绑定到一个session中的对象都可以被任何属于同一个ServletContext的servlet访问,并且能够把请求绑定到它的会话中。

一些对象当它们被放入一个会话,或从会话中删除时,它们也许需要通知。这些信息可以通过将这些对象实现HttpSessionBindingListener 接口实现。这个接口定义了下面的方法来通知对象,当它被绑定到一个会话或被解除绑定。

  • valueBound
  • valueUnbound

valueBound方法必须在对象被HttpSession接口的getAttribute方法变为可用的之前调用。valueUnbound 方法必须在对象不再通过HttpSession接口的getAttribue方法调用之后调用。


7.5 Session 过期

在HTTP协议中,当用户不再活跃时是没有明确的终止信号的。这意味着标志用户不再活跃的唯一机制是超时。

默认的会话超时时间是由servlet容器定义的,并且可以通过HttpSession接口的getMaxInactiveInterval方法获得。用户也可以通过HttpSession接口的setMaxInactiveInterval方法改变超时时间。这些方法设置的时间是以秒为单位的。根据定义,如果会话的超时时间被设置为0或者负数,那么会话就永远不会过期。直到所有使用这个会话的servlet都退出了service方法,
session才有可能会失效。一旦会话过期了,新的请求一定是不能看到这个会话的。


7.6 上次访问时间

一个Servlet能够通过HttpSession接口的getLastAccessedTime方法确定会话上次被访问的时间。当会话中的一个请求第一次被servlet容器处理时,就认为进入了一个会话。


7.7 一些重要的会话语义

7.7.1 线程问题

执行请求的多个线程可能同时访问同一个session对象。容器必须确保操作session属性的内部数据结构是线程安全的。开发者要自己负责线程安全的使用这些对象。要保证HttpSession对象中的集合属性被安全的并发使用,避免出现应用程序破坏这些集合的机会。

7.7.2 分布式的环境

在一个分布式的系统中,一个会话的所有请求在一个时间只能被一个JVM处理。容器必须能够合适地处理所有的放入HttpSession实例中的对象。下面的这些限制条件必须被满足:

  • 容器必须能够接受实现了Serializable接口的对象
  • 容器可以选择性的支持存储其他指定的对象在HttpSession中,例如事务和JavaBeans的引用。
  • 会话的迁移要被容器指定的设施处理

分布式的servlet容器必须支持迁移实现了Serializable接口的对象的机制。

这些限制意味着确保了开发者不会比在非分布式容器中遇到更多的并发问题。

容器提供者能确保可伸缩性和服务的质量,如负载均衡和故障转义,它能将session对象和它的内容从分布式中的一个活动节点转移到系统中的其它节点中去。

如果分布式容器能够为保存和转移会话提供服务保证,它们就不会限制于使用本地JVM序列化机制来序列化HttpSession和它们的属性。开发者不能确保容器会调用readObject和writeObject方法在session属性上,但可以被保证序列化对象在关闭时可以被保存。

容器必须在会话迁移时通知实现了HttpSessionActivationListener接口的会话属性。它们必须在序列化会话前通知钝化监听器,在反序列化会话后通知激活监听器。

编写分布式应用的开发者应该清楚因为容器可以在多个JVM中运行,开发者不能依靠静态变量来存储系统状态。他们应该通过bean或数据库来存储这些状态。

7.7.3 客户端语义

因为cookies和SSL证书通常被Web浏览器控制并且没有和任何特定的浏览器窗口关联,从所有窗口的客户端应用的所有请求可能是同一个会话。为了最大的可移植性,开发者应该始终认为客户端的所有窗口都参与同一个会话。