Java 进阶 (十五)Java 中设置 session 的详细解释
简单通俗的讲 session 就是象一个临时的容器,用来存放临时的东西。从你登陆开始就保存在 session 里,当然你可以自己设置它的有效时间和页面,举个简单的例子:我们做一个购书的 JSP 网站,顾客买书的时候会挑选出一些书,但是在付钱之前还可以修改,所以不能存到数据库。就可以先保存在 session 里,等到确认了以后再放入数据库...
一、cookie 和 session 机制之间的差别和联系
让我们用几个例子来描述一下 cookie 和 session 机制之间的差别和联系。笔者原来常去的一家咖啡店有喝 5 杯咖啡免费赠一杯咖啡的优惠,然而一次性消费 5 杯咖啡的机会微乎其微,这时就需要某种方式来纪录某位顾客的消费数量。想象一下其实也无外乎下面的几种方案:
1、该店的店员非常厉害,能记住每位顾客的消费数量,只要顾客一走进咖啡店,店员就知道该怎么对待了。这种做法就是协议本身支持状态。
2、发给顾客一张卡片,上面记录着消费的数量,一般更有个有效期限。每次消费时,如果顾客出示这张卡片,则此次消费就会和以前或以后的消费相联系起来。这种做法就是在客户端保持状态。
3、发给顾客一张会员卡,除了卡号之外什么信息也不纪录,每次消费时,如果顾客出示该卡片,则店员
在店里的纪录本上找到这个卡号对应的纪录添加一些消费信息。这种做法就是在服务器端保持状态。
由于 HTTP 协议是无状态的,而出于种种考虑也不希望使之成为有状态的,因此,后面两种方案就成为现实的选择。具体来说 cookie 机制采用的是在客户端保持状态的方案,而 session 机制采用的是在服务器端保持状态的方案。同时我们也看到,由于采用服务器端保持状态的方案在客户端也需要保存一个标识,所以 session 机制可能需要借助于 cookie 机制来达到保存标识的目的,但实际上他更有其他选择。
二、理解 cookie 机制
cookie 机制的基本原理就如上面的例子相同简单,不过更有几个问题需要解决:“会员卡”怎么分发;“会员卡”的内容;及客户怎么使用“会员卡”。
正统的 cookie 分发是通过扩展 HTTP 协议来实现的,服务器通过在 HTTP 的响应头中加上一行特别的指示以提示浏览器按照指示生成相应的 cookie。然而纯粹的客户端脚本如 JavaScript 或 VBScript 也能生成 cookie。
而 cookie 的使用是由浏览器按照一定的原则在后台自动发送给服务器的。浏览器检查所有存储的 cookie,如果某个 cookie 所声明的作用范围大于等于将要请求的资源所在的位置,则把该 cookie 附在请求资源的 HTTP 请求头上发送给服务器。意思是麦当劳的会员卡只能在麦当劳的店里出示,如果某家分店还发行了自己的会员卡,那么进这家店的时候除了要出示麦当劳的会员卡,还要出示这家店的会员卡。
cookie 的内容主要包括:名字,值,过期时间,路径和域。
其中域能指定某一个域比如.google.com,相当于总店招牌,比如宝洁公司,也能指定一个域下的具体某台机器比如 www.google.com 或 froogle.google.com,能用飘柔来做比。
路径就是跟在域名后面的 URL 路径,比如/或/foo 等等,能用某飘柔专柜做比。
路径和域合在一起就构成了 cookie 的作用范围。
如果不设置过期时间,则表示这个 cookie 的生命期为浏览器会话期间,只要关闭浏览器窗口,cookie 就消失了。这种生命期为浏览器会话期的 cookie 被称为会话 cookie。会话 cookie 一般不存储在硬盘上而是保存在内存里,当然这种行为并不是规范规定的。如果设置了过期时间,浏览器就会把 cookie 保存到硬盘上,关闭后再次打开浏览器,这些 cookie 仍然有效直到超过设定的过期时间。
存储在硬盘上的 cookie 能在不同的浏览器进程间共享,比如两个 IE 窗口。而对于保存在内存里的 cookie,不同的浏览器有不同的处理方式。对于 IE,在一个打开的窗口上按 Ctrl-N(或从文件菜单)打开的窗口能和原窗口共享,而使用其他方式新开的 IE 进程则不能共享已打开的窗口的内存 cookie;对于 Mozilla Firefox0.8,所有的进程和标签页都能共享同样的 cookie。一般来说是用 javascript 的 window.open 打开的窗口会和原窗口共享内存 cookie。浏览器对于会话 cookie 的这种只认 cookie 不认人的处理方式经常给采用 session 机制的 web 应用程式研发者造成非常大的困扰。
下面就是个 goolge 设置 cookie 的响应头的例子
这是使用 HTTPLook 这个 HTTP Sniffer 软件来俘获的 HTTP 通讯纪录的一部分。浏览器在再次访问 goolge 的资源时自动向外发送 cookie。使用 Firefox 能非常容易的观察现有的 cookie 的值。使用 HTTPLook 配合 Firefox 能非常容易的理解 cookie 的工作原理。IE 也能设置在接受 cookie 前询问,这是个询问接受 cookie 的对话框。
三、理解 session 机制
session 机制是一种服务器端的机制,服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。
当程式需要为某个客户端的请求创建一个 session 的时候,服务器首先检查这个客户端的请求里是否已包含了一个 session 标识 - 称为 session id,如果已包含一个 session id 则说明以前已为此客户端创建过 session,服务器就按照 session id 把这个 session 检索出来使用(如果检索不到,可能会新建一个),如果客户端请求不包含 session id,则为此客户端创建一个 session 并且生成一个和此 session 相关联的 session id。
保存这个 session id 的方式能采用 cookie,这样在交互过程中浏览器能自动的按照规则把这个标识发挥给服务器。一般这个 cookie 的名字都是类似于 SEEESIONID。比如 weblogic 对于 web 应用程式生成的 cookie。
由于 cookie 能被人为的禁止,必须有其他机制以便在 cookie 被禁止时仍然能够把 session id 传递回服务器。经常被使用的一种技术叫做 URL 重写,就是把 session id 直接附加在 URL 路径的后面,附加方式也有两种,一种是作为 URL 路径的附加信息,表现形式为http://...../xxx;jsessionid=ByOK ... 99zWpBng!-145788764
另一种是作为查询字符串附加在 URL 后面,表现形式为http://...../xxx?jsessionid=ByOK ... 99zWpBng!-145788764
这两种方式对于用户来说是没有差别的,只是服务器在解析的时候处理的方式不同,采用第一种方式也有利于把 session id 的信息和正常程式参数区分开来。
为了在整个交互过程中始终保持状态,就必须在每个客户端可能请求的路径后面都包含这个 session id。
另一种技术叫做表单隐藏字段。就是服务器会自动修改表单,添加一个隐藏字段,以便在表单提交时能够把 session id 传递回服务器。
这种技术目前已较少应用,笔者接触过的非常古老的 iPlanet6(SunONE 应用服务器的前身)就使用了这种技术。实际上这种技术能简单的用对 action 应用 URL 重写来代替。
在谈论 session 机制的时候,常常听到这样一种误解“只要关闭浏览器,session 就消失了”。其实能想象一下会员卡的例子,除非顾客主动对店家提出销卡,否则店家绝对不会轻易删除顾客的资料。对 session 来说也是相同的,除非程式通知服务器删除一个 session,否则服务器会一直保留,程式一般都是在用户做 log off 的时候发个指令去删除 session。然而浏览器从来不会主动在关闭之前通知服务器他将要关闭,因此服务器根本不会有机会知道浏览器已关闭,之所以会有这种错觉,是大部分 session 机制都使用会话 cookie 来保存 session id,而关闭浏览器后这个 session id 就消失了,再次连接服务器时也就无法找到原来的session
。如果服务器设置的 cookie 被保存到硬盘上,或使用某种手段改写浏览器发出的 HTTP 请求头,把原来的 session id 发送给服务器,则再次打开浏览器仍然能够找到原来的 session。
恰恰是由于关闭浏览器不会导致 session 被删除,迫使服务器为 seesion 设置了一个失效时间,当距离客户端上一次使用 session 的时间超过这个失效时间时,服务器就能认为客户端已停止了活动,才会把 session 删除以节省存储空间。
四、理解 javax.servlet.http.HttpSession
HttpSession 是 Java 平台对 session 机制的实现规范,因为他仅仅是个接口,具体到每个 web 应用服务器的提供商,除了对规范支持之外,仍然会有一些规范里没有规定的细微差异。这里我们以 BEA 的 Weblogic Server8.1 作为例子来演示。
首先,Weblogic Server 提供了一系列的参数来控制他的 HttpSession 的实现,包括使用 cookie 的开关选项,使用 URL 重写的开关选项,session 持久化的设置,session 失效时间的设置,及针对 cookie 的各种设置,比如设置 cookie 的名字、路径、域,cookie 的生存时间等。
一般情况下,session 都是存储在内存里,当服务器进程被停止或重启的时候,内存里的 session 也会被清空,如果设置了 session 的持久化特性,服务器就会把 session 保存到硬盘上,当服务器进程重新启动或这些信息将能够被再次使用,Weblogic Server 支持的持久性方式包括文件、数据库、客户端 cookie 保存和复制。
复制严格说来不算持久化保存,因为 session 实际上还是保存在内存里,不过同样的信息被复制到各个 cluster 内的服务器进程中,这样即使某个服务器进程停止工作也仍然能从其他进程中取得 session。
cookie 生存时间的设置则会影响浏览器生成的 cookie 是否是个会话 cookie。默认是使用会话 cookie。有兴趣的能用他来试验我们在第四节里提到的那个误解。
cookie 的路径对于 web 应用程式来说是个非常重要的选项,Weblogic Server 对这个选项的默认处理方式使得他和其他服务器有明显的差别。
版权声明: 本文为 InfoQ 作者【No Silver Bullet】的原创文章。
原文链接:【http://xie.infoq.cn/article/e6f1f59f79e63945f6844d3ff】。文章转载请联系作者。
评论