会话
因为超文本传输协议(HTTP)是无状态协议,为了构件有效的Web应用,使来自一个特定的客户端的请求彼此相关联是必要的。因此逐渐演变出了会话跟踪机制。Servlet规范定义了一个简单的HttpSession接口,允许servlet容器使用几种方法来跟踪用户会话。
会话跟踪机制
Cookie
通过cookie进行会话跟踪是最常用的,且所有servlet都支持。
容器向客户端发送一个cookie,客户端后续到服务器的请求都将返回该cookie,明确地将请求与会话关联。会话跟踪cookie的标准名字必须是JSESSIONID。容器也允许通过容器指定配置来自定义跟踪cookie的名字。
所有servlet容器必须能提供配置容器是否标记会话跟踪cookie为HttpOnly的能力。已建立的配置必须应用到所有上下文中还没有建立特定的配置。
若自定义了会话跟踪cookie的名字,则会话id编码到URL中,那么相同的自定义名字也将用于URI参数的名字。
SSL会话
安全套接字层,在HTTPS使用的加密技术中,有一种内置机制可以允许多个来自客户端的请求被明确识别为同一会话。
URL重写
URL重写是会话跟踪的最低标准。当客户端不接受cookie时,服务器可使用URL重写作为会话跟踪的基础。URL重写涉及数据添加、会话ID和容器解析URL路径,从而请求与会话相关联。
会话ID必须编码为URL字符串中的一个路径参数,参数名必须是JSESSIONID。
URL重写在日志、书签、referer header、缓存的HTML、URL工具条中会暴露会话标识,因此在支持cookie或SSL会话的情况下,不应该使用URL重写作为会话跟踪机制。
会话完整性
当服务来自客户端的请求不支持使用cookie是,Web容器必须能够支持HTTP会话。因此Web容器通常支持URL重写机制。
创建会话
当会话仅是一个未来的且还没有被建立时,它被认为是“新”的。因为HTTP是基于请求-响应的协议,知道客户端“加入”到HTTP会话之前,它都被认为是新的。当会话跟踪信息返回到服务器来指示会话已经建立客户端加入到会话。直到客户端加入到会话,不能假定下一个来自客户端的请求别识别为同一会话。
如果客户端还不知道会话或者客户端选择不加入会话,则会话被认为是“新”的。servlet开发人员必须设计他的应用以便处理客户端没有,不能,或不会加入会话的情况。一个包含唯一标识符的字符串与每个会话相关联,称为会话ID,它的值可以通过HttpSession.getId()
获取,能在创建后通过HttpServletRequest.changeSessionId()
改变。
会话范围
HttpSession对象必须被限定在应用或Servlet上下文级别。如使用cookie建立会话,不同的上下文可以是相同,但所引用的对象,包括该对象中的属性,决不能在容器上下文之间共享。例如:servlet使用RequestDispatcher来调用另一个Web应用的servlet,任何创建的会话和被调用servlet所见的必须不同于来自调用会话所见的。此外,一个上下文的会话在请求进入那个上下文时必须是可恢复的,不管是直接访问他们关联的上下文,还是在请求目标分派时创建的会话。
绑定属性到会话
servlet可以按名称绑定对象属性到HttpSession实现,任何绑定到会话的对象可用于任意其他的servlet,其属于同一个ServletContext且处理属于相同会话中的请求。一些对象可能需要在他们被放进会话或从会话中移除时得到通知。这些信息可以从HttpSessionBindingListener接口实现的对象中获取,该接口定义了valueBound()方法用于标识一个对象被绑定,valueUnbound()来将对象从会话解除绑定。在HttpSession接口的getAttribute方法可用之前,valueBound方法必须被调用;在getAttribute方法不可用之后,valueUnbound方法必须被调用。
会话超时
当客户端不在处于活动状态时没有显式的终止信号,此时可以使用的唯一机制是超时时间。
Servlet容器定义了默认的会话超时时间,可以通过HttpSession.getMaxInactiveInterval方法获取,可以使用HttpSession.setMaxInactionInterval改变。这些方法的超时时间以秒为单位,如果设置为0 或更小的值,会话将永不过期,直到所有servlet使用的会话已经退出其service方法。一旦会话失效,心的请求必须不能看到该会话。
最后访问时间
HttpSession结构的getLastAccessedTime方法允许servlet确定在当前请求之前的最后访问时间,当会话中的请求时servlet容器第一个处理时,该会话被认为是访问了。
重要会话语义
多线程问题
容器必须确保,以一种线程安全你的方式维护表示会话属性的内部数据结构,开发者负责线程安全的访问属性对象本身。
分布式环境
在一个标识为分布式应用程序中,会话的所有请求在同一时间必须仅被一个JVM处理。容器必须能够使用适当的setAttribute或putValue方法把所有对象放入到HttpSession类实例。因此使用以下限制:
- 容器必须接受实现了Serializable接口的对象
- 容器可以选择支持其他指定对象存储在HttpSession中,如Enterprise JavaBeans组件和事物的引用。
- 由特定容器的设施处理会话迁移。
当分布式servlet不支持必须的会话迁移存储对象机制时,容器必须抛出IllegalStateException。
容器必须在迁移会话时通知实现了HttpSessionActivationListerner的所有会话属性。他们必须在序列化会话之前通知钝化监听器,在反序列化之后通知激活监听器。
分布式应用中容器可能运行在多个Java虚拟机中,不能依赖静态变量存储应用状态。应该使用企业Bean或数据库存储这种状态。
客户端语义
由于cookie或SSL证书通常由Web浏览器进程控制,且不与浏览器的任意特定窗口关联,从客户端应用程序发起的到servlet容器的请求可能在同一会话。为了最大的可移植性,开发者应该假定客户端所有窗口都参与同一会话。
参考链接: 来自waylau翻译的《Java Servlet 3.1 规范》
自己使用整理收集,如有侵权 请联系删除!