servlet2.3规范之七——会话

7 会话

超文本传输协议(Hypertext Transfer ProtocolHTTP)被设计为无状态的协议。要构建有效的web应用,必须将来自某个特定客户端的请求互相关联。长时间以来,出现了多种策略解决会话跟踪问题,但是所有这些对于程序员直接使用都是有困难的,或者很麻烦。

本规范定义了一个简单的HttpSession接口,允许servlet容器使用其中任何一种方案来跟踪用户会话,而不至于让应用开发人员陷入任何方案的细微差别。

7.1 会话跟踪机制

以下部分描述跟踪用户会话的方案。

7.1.1 Cookie

通过HTTP cookie跟踪会话是一种最常用的会话跟踪机制,要求所有的servlet容器都支持。

容器向客户端发送cookie,然后客户端向服务器返回接下来每一个请求的cookie,明确地将请求和会话进行关联。会话跟踪cookie的名称必须是JSESSIONID

7.1.2 SSL会话

SSLSecure Sockets Layer,安全套接字层),HTTPS协议中使用的加密技术,内嵌了一种机制,使得来自一个客户端的多个请求能明确识别为属于某个会话。Servlet容器可以容易地使用这些数据定义会话。

7.1.3 URL重写

URL重写是一种最为大家好理解的会话跟踪。当客户端不接受cookie时,服务器就使用URL重写作为会话跟踪的基础。URL重写涉及添加数据,会话id,由容器解释的URL路径和会话的请求关联。

会话id必须被编码,作为URL字符串中的path参数,参数的名称必须为jsessionid。这是一个包含编码后的path信息的URL示例:

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

7.1.4 会话完整性

web容器必须在处理来自不支持cookie客户端的HTTP请求时,能够支持HTTP会话。要满足这项要求,web容器通常支持URL重写机制。

7.2 创建一个会话

只有当会话是一个预期的会话,并且还没有构建时,才被认为是“新的”。因为HTTP是一种基于请求-响应的协议,直到有客户端“加入(join)”HTTP会话时,才被认为是新的。当会话跟踪信息已经返回给服务器,表明已经构建一个会话时,客户端加入会话。除非客户端加入了会话,否则不会假定来自客户端的下一个请求属于某个会话。

如果下列有一项为true,则会话被认为是“新的”:

客户端还不知道会话

客户端选择不加入会话

这些条件定义了servlet容器无法将某个请求和原请求关联的情形。

Servlet开发人员必须设计他的应用处理这样一种情况:客户端还没有,不能或者不加入某个会话。

7.3 会话作用域

HttpSession对象必须作用于应用(或者servlet上下文)级。底层机制,比如用来构建会话的cookie,对于不同的上下文可以是相同的,但是会话所引用的,包括会话中的属性,不可以在容器的上下文间共享。

用一个例子来说明该项需求:如果servlet使用RequestDispatcher调用另一个web应用的servlet,那么为调用方servlet创建的会话必须和被调用方servlet的不同。

7.4 将属性绑定到会话

servlet可以通过名称将一个对象属性绑定到一个HttpSession实现。任何绑定到会话的对象对于属于同一个ServletContext的任何servlet都是可用的,并且将请求标识为属于同一个会话。

有些对象在它们被放入会话或者从会话中删除时可能需要得到通知,可以让该对象实现HttpSessionBindingListener接口来实现。该接口定义了下列方法,向要被绑定到会话,或要从会话中解除绑定的对象发出信号。

• valueBound

• valueUnbound

valueBound方法调用之后,可以通过HttpSession接口的getAttribute方法获得该对象。valueUnbound方法调用之后,不再可以通过HttpSession接口的getAttribute方法获得该对象。

7.5 会话超时

HTTP协议中,当一个客户端不再活动时,没有显式的终止信号。这意味着只能使用超时时间段这样唯一一个机制表示一个客户端不再活动。

默认的超时时间段由servlet容器定义,可以通过HttpSession接口的getMaxInactiveInterval方法获得。开发人员可以使用HttpSession接口的setMaxInactiveInterval方法修改超时时间段。这些方法使用的超时时间段定义为秒。根据定义,如果会话超时时间段设为-1,则会话永远不会超时。

7.6 最近访问时间

HttpSession接口的getLastAccessedTime方法允许servlet确定在当前请求之前上一次访问会话的时间。当属于会话的请求第一次由servlet容器处理时,认为该会话被访问。

7.7 重要的会话语义

7.7.1 线程问题

可能有多个执行请求线程的servlet同时访问单个会话。开发人员要负责适当时候同步(synchronize)对会话资源的访问。

7.7.2 分布式环境

在分布式应用中,所有属于某个会话的请求都必须由一个虚拟机一次处理。容器必须能正确地使用setAttribute或者putValue方法处理放入HttpSession类实例的所有对象。为满足这些条件,强行做以下限定:

容器必须接受实现Serializable接口的对象

容器可以选择支持在HttpSession中存储其他指定的对象,比如EJB组件和事务的引用。

会话迁移将由容器特定的工具处理。

如果放入会话的对象不是序列化(Serializable)的,或者某个特定的支持不可用,servlet容器可能抛出IllegalArgumentException异常。如果因为容器不支持会话迁移所必需的机制(存储这些对象),则必须抛出IllegalArgumentException异常。

这些限定意味着开发人员要确保除了在非分布式容器中遇到的问题之外,不会再有其他的并发问题。

拥有从分布式系统的任一个活跃节点移动到系统的另一个节点迁移session对象及其内容的能力,容器供应商可以确保可伸缩,高质量的服务,比如负载均衡和失败恢复。

如果分布式容器对会话持久化或者迁移以提供高品质的服务,那么不会限制它们使用本地JVM序列化机制来序列化HttpSession和它们的属性。开发人员不会有这样的保证,如果实现了的话,容器将调用session属性的readObjectwriteObject方法,但是可以保证,属性的序列化关闭将被保留。

在会话迁移期间容器必须通知任何实现HttpSessionActivationListener的会话。它们必须先通知监听器会话钝化,后通知会话序列化,先通知会话解序列化,后通知会话激活。

编写分布式应用的应用开发人员应当意识到因为容器可以运行在多个Java虚拟机上,开发人员不能依赖于存储application状态的静态变量,而应当使用EJB或者数据库存储状态。

7.7.3 客户端语义

因为cookies或者SSL认证通常由web浏览器进程控制,不和浏览器任何特定窗口关联,来自一个客户端应用的所有窗口到servlet容器的请求可能是属于同一个会话。为了尽量简便,开发人员应当始终假定客户端的所有窗口属于同一个会话。

你可能感兴趣的:(应用服务器,Web,浏览器,servlet,ejb)