Web 开发中的 Session

本贴最后更新于 2253 天前,其中的信息可能已经时移世易

原文

扩展

Session 是 WEB 上有效的信息交互手段,因其使用方便、稳定、安全、可靠而被众多 WEB 开发者所认知。尤其在互联网身份验证、网上电子购物等方面的应用更为广泛。下面就着重来介绍下 Session。

Session


Session,在汉语中表示通话、会话、对话(期)、话路[对谈时间]的意思,其本来的含义一个终端用户与交互系统进行通信的时间(间隔),通常是指从注册(进入系统)到注销(退出系统)之间所经过的时间。比如打电话时从拿起电话拨号到挂断电话这中间的一系列过程可以称之为一个 Session。有时候我们可以看到这样的话“在一个浏览器会话期间,…”,这里的会话一词用的就是这个意思,是指从一个浏览器窗口打开到关闭这个期间。Session 在我们的网络应用中就是一种客户端与服务器端保持状态的解决方案,有时候 Session 也用来指这种解决方案的存储结构, Session 对象,就是客户端浏览器与服务器之间建立的互动信息状态。每一个不同的用户连接将得到不同的 Session,也就是说 Session 与用户之间是一种一对一的关系。Session 在用户进入网站时由服务器自动产生,并在用户正常离开站点时释放。使用 Session 的好处就在于,可以将很多与用户相关的信息,例如用户的帐号、昵称等保存到 Session 中;利用 Session,可以跟踪用户在网站上的活动。例如:当你上网进入一个网站时,如果你没有登陆,无论你访问哪几个页面都会跳转回登陆页。还有就是你在购物时,不可能把你的东西放到别人的购物车里去,这就得用一个信息变量来判断!
如果能够提供一些按需生成的动态信息会使 web 变得更加有用,就像给有线电视加上点播功能一样。这种需求一方面迫使 HTML 逐步添加了表单、脚本、DOM 等客户端行为,另一方面在服务器端则出现了 CGI 规范以响应客户端的动态请求,作为传输载体的 HTTP 协议也添加了文件上载、cookie 这些特性。其中 cookie 的作用就是为了解决 HTTP 协议无状态的缺陷所作出的努力。至于后来出现的 Session 机制则是又一种在客户端与服务器之间保持状态的解决方案。
从不同的层面看待 Session,它有着类似但不全然相同的含义。比如,在 web 应用的用户看来,他打开浏览器访问一个电子商务网站,登录、并完成购物直到关闭浏览器,这是一个会话。而在 web 应用的开发者开来,用户登录时我需要创建一个数据结构以存储用户的登录信息,这个结构也叫做 session。因此在谈论 session 的时候要注意上下文环境。而本文谈论的是一种基于 HTTP 协议的用以增强 web 应用能力的机制或者说一种方案,它不是单指某种特定的动态页面技术,而这种能力就是保持状态,也可以称作保持会话。

Cookies


Cookie 是 WEB 上最常用的跟踪用户会话方式,当 Cookie 被禁止后,一般都用 URL 重写来跟踪会话。Cookie 是一种由服务器发送给客户的片段信息,存储在客户环境中,并在客户所有的对服务器的请求中都要发回它。就好比我们在用 IE 登陆某个电子购物商城时,IE 在得到商品列表页面的 同时还收到Set-Cookie应答头信息,我们打开一个 Cookie 文件,我们所看到的格式一般都是:
Cookie:NAME=VALUE;Comment=COMMENT;Domain=DOMAINNMAM;Max-age=SECONDS;Path=PATH;secure;Version=1*DIGIT
其中 NAME 值对(值对间用分号分隔)是必须的,其余都是可选的。最重要的信息当然也在所必须的值对里了,VALUE 是 NAME 的值,也是这个 Cookie 的标识,Max-age 定义了 Cookie 的最长生存时间,其它几个可选值对可参阅 RFC 2109 - HTTP State Management Mechanism。当我们选购了某种商品,向服务器发送选购清单时,会自动在你的请求信息头里加上 NAME 值对,如果 Cookie 被禁止,则用 URL 重写方式在 URL 请求地址上附加 NAME 值对。当 Web 服务器收到这个请求后,会检查该 Cookie 是否存在,然后相应的跟踪会话。从以上分析不难理解,其实 Web 服务器跟踪会话就靠Set-Cookie头信息,跟踪 NAME 值对进行身份验证。假如我们用非 Web 终端接收 Web 服务器的响应信息,从中解析出 Cookie 头信息,当再次向 Web 服务器发送请求时附加上解析出的 Cookie 信息,Web 服务器据此不就可以进行身份认证了吗?

Cookies 中文是饼干的意思,对于为何引用 Cookies,从网上查找了一些资料:
在浏览器与 WEB 服务器之间是使用 HTTP 协议进行通信的,当某个用户发出页面请求时,WEB 服务器只是简单的进行响应,然后就关闭与该用户的连接。因此当一个请求发送到 WEB 服务器时,无论其是否是第一次来访,服务器都会把它当作第一次来对待,这样的不好之处可想而知。为了弥补这个缺陷,Netscape【网景】开发出了 cookie 这个有效的工具来保存某个用户的识别信息,因此人们昵称为“小甜饼”。cookies 是一种 WEB 服务器通过浏览器在访问者的硬盘上存储信息的手段:Netscape Navigator 使用一个名为 cookies.txt 本地文件保存从所有站点接收的 Cookie 信息;而 IE 浏览器把 Cookie 信息保存在类似于 c:\Internet 临时文件\\ 的目录下。当用户再次访问某个站点时,服务端将要求浏览器查找并返回先前发送的 Cookie 信息,来识别这个用户。Cookies 给网站和用户带来的好处:

  1. Cookie 能使站点跟踪特定访问者的访问次数、最后访问时间和访问者进入站点的路径
  2. Cookie 能告诉在线广告商广告被点击的次数,从而可以更精确的投放广告
  3. Cookie 有效期限未到时,Cookie 能使用户在不键入密码和用户名的情况下进入曾经浏览过的一些站点
  4. Cookie 能帮助站点统计用户个人资料以实现各种各样的个性化服务,其实,cookie 的作用就是为了解决 HTTP 协议无状态的缺陷所作的努力.

Cookie 机制


Cookie 机制采用的是在客户端保持状态的方案。
Cookie 机制,就是当服务器对访问它的用户生成了一个 Session 的同时服务器通过在 HTTP 的响应头中加上一行特殊的指示以提示浏览器按照指示生成相应的 Cookie,保存在客户端,里面记录着用户当前的信息,当用户再次访问服务器时,浏览器检查所有存储的 Cookie,如果某个 Cookie 所声明的作用范围大于等于将要请求的资源所在的位置也就是对应的 Cookie 文件。 若存在,则把该 cookie 附在请求资源的 HTTP 请求头上发送给服务器,例如:当我们登陆了一个网站,并且填写了有关资料,以本站会员的名义登陆上了有关网页,这时你把浏览器关闭,再重启进入该网站的某一个页面时是以你登陆过的会员进去的,当然,不是所有网站都是这样,我们知道,Cookie 的保存有临时性的和持久性的,大多都是临时性的,也就是 Cookie 只保存在客户端的内存中,而没有保存在硬盘上,当关闭浏览器,Cookie 也就销毁。以下是有关 Cookie 机制的一些具体说明:
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;对于火狐狸 firefox 浏览器,所有的进程和标签页都可以共享同样的 Cookie。一般来说是用 javascript 的 window.open 打开的窗口会与原窗口共享内存 Cookie。浏览器对于会话 Cookie 的这种只认 Cookie 不认人的处理方式经常给采用 Session 机制的 web 应用程序开发者造成很大的困扰。

Session 机制


Session 机制采用的是在服务器端保持状态的方案。
当用户访问到一个服务器,服务器就要为该用户创建一个 Session,在创建这个 Session 的时候,服务器首先检查这个用户发来的请求里是否包含了一个 Session id,如果包含了一个 Session id 则说明之前该用户已经登陆过并为此用户创建过 Session,那服务器就按照这个 Session id 把这个 Session 在服务器的内存中查找出来(如果查找不到,就有可能为他新创建一个),如果客户端请求里不包含有 Session id,则为该客户端创建一个 Session 并生成一个与此 Session 相关的 Session id。这个 Session id 是唯一的、不重复的、不容易找到规律的字符串,这个 Session id 将被在本次响应中返回到客户端保存,而保存这个 Session id 的正是 Cookie,这样在交互过程中浏览器可以自动的按照规则把这个标识发送给服务器。
我们知道在 IE 中,我们可以在工具的 internet 选项中把 Cookie 禁止,那么会不会出现把客户端的 Cookie 禁止了,Session id 就无法再用了呢?找了一些资料说明,可以有其他机制在 Cookie 被禁止时仍然能够把 Session id 传递回服务器。经常被使用的一种技术叫做 URL 重写,就是把 Session id 直接附加在 URL 路径的后面一种是作为 URL 路径的附加信息,表现形式为:
http://…./xxx;jSession=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764;
另一种是作为查询字符串附加在 URL 后面,表现形式为:
http://…../xxx?jSession=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764
还有一种就是表单隐藏字段。就是服务器会自动修改表单,添加一个隐藏字段,以便在表单提交时能够把 Session id 传递回服务器。这里就不介绍了。
我们常说的在一个 IE 被打开是创建一个 Session,当关闭 IE 时 Session 也就被删除,事实上,除非程序通知服务器删除 Session,否则 Session 会被服务器一直保留,直到 Session 的失效时间到了自动删除。服务器不知道 IE 被关闭,IE 不会主动在其关闭之前通知服务器它将要关闭。程序一般都是在用户做注销时删除 Session。我们产生这种错觉的原因是:***一般 Session 机制都使用 Cookie 来保存 Session id,而一旦关闭 IE 浏览器,Session id 就不存在了,再连接服务器时找不到原来的 Session 了.如果服务器设置的 Cookie 被保存到硬盘上,或者使用某种手段改写浏览器发出的 HTTP 请求头,把原来的 Session id 发送给服务器,则再次打开浏览器仍然能够找到原来的 Session。***恰恰是由于关闭浏览器不会导致 Session 被删除,迫使服务器为 seesion 设置了一个失效时间,当距离客户端上一次使用 Session 的时间超过这个失效时间时,服务器就可以认为客户端已经停止了活动,才会把 Session 删除以节省存储空间。
一般情况下,Session 都是存储在内存里,当服务器进程被停止或者重启的时候,内存里的 Session 也会被清空,如果设置了 Session 的持久化特性,服务器就会把 Session 保存到硬盘上,当服务器进程重新启动或这些信息将能够被再次使用。

Cookie 机制与 Session 机制的区别和联系


Cookie 机制采用的是在客户端保持状态的方案,而 Session 机制采用的是在服务器端保持状态的方案。同时我们也看到,由于在服务器端保持状态的方案在客户端也需要保存一个标识,所以 Session 机制可能需要借助于 cookie 机制来达到保存标识的目的,但实际上还有其他选择。例如,我们经常用到的会员卡,也就相当于这种情况。消费到了一定程度就有奖,就如下面例子说明:

  1. 发给顾客一张卡片,上面记录着消费的数量,一般还有个有效期限。每次消费时,如果顾客出示这张卡片,则此次消费就会与以前或以后的消费相联系起来。这种做法就是在客户端保持状态。
  2. 发给顾客一张会员卡,除了卡号之外什么信息也不纪录,每次消费时,如果顾客出示该卡片,则店员在店里的纪录本上找到这个卡号对应的纪录添加一些消费信息。这种做法就是在服务器端保持状态。

以下是一些关于两者的区别与联系:
具体来说 Cookie 是在用户端的会话状态的存贮机制,他需要用户打开客户端的 Cookie 支持。Cookie 的作用就是为了解决 HTTP 协议无状态的缺陷所作的努力.而 Session 机制采用的是一种在客户端与服务器之间保持状态的解决方案。同时我们也看到,由于采用服务器端保持状态的方案在客户端也需要保存一个标识,所以 Session 机制可能需要借助于 Cookie 机制来达到保存标识的目的。而 Session 提供了方便管理全局变量的方式。
Session 是针对每一个用户的,变量的值保存在服务器上,用一个 Session 来区分是哪个用户 Session 变量,这个值是通过用户的浏览器在访问的时候返回给服务器,当客户禁用 Cookie 时,这个值也可能设置为由 get 来返回给服务器。
就安全性来说:当你访问一个使用 Session 的站点,同时在自己机子上建立一个 Cookie,建议在服务器端的 Session 机制更安全些.因为它不会任意读取客户存储的信息。
正统的 cookie 分发是通过扩展 HTTP 协议来实现的,服务器通过在 HTTP 的响应头中加上一行特殊的指示以提示浏览器按照指示生成相应的 cookie。
从网络服务器观点看所有 HTTP 请求都独立于先前请求。就是说每一个 HTTP 响应完全依赖于相应请求中包含的信息.
状态管理机制克服了 HTTP 的一些限制并允许网络客户端及服务器端维护请求间的关系。在这种关系维持的期间叫做会话(Session)。
Cookies 是服务器在本地机器上存储的小段文本并随每一个请求发送至同一个服务器。IETF RFC 2965 HTTP State Management Mechanism 是通用 Cookie 规范。网络服务器用 HTTP 头向客户端发送 cookies,在客户终端,浏览器解析这些 cookies 并将它们保存为一个本地文件,它会自动将同一服务器的任何请求缚上这些 cookies 。
来看一下 Tomcat 是如何实现 web 应用程序之间 Session 的隔离的,从 Tomcat 设置的 Cookie 路径来看,它对不同的应用程序设置的 Cookie 路径是不同的,这样不同的应用程序所用的 Session id 是不同的,因此即使在同一个浏览器窗口里访问不同的应用程序,发送给服务器的 Session id 也可以是不同的。

常见问题


  1. Session 在何时被创建
    Session 在有客户端访问时就被创建,然而事实是直到某 server 端程序调用 HttpServletRequest.getSession(true) 这样的语句时才被创建,注意如果 JSP 没有显示的使用 <%@page Session=”false”%> 关闭 Session,则 JSP 文件在编译成 Servlet 时将会自动加上这样一条语句 HttpSession Session = HttpServletRequest.getSession(true); 这也是 JSP 中隐含的 Session 对象的来历。由于 Session 会消耗内存资源,因此,如果不打算使用 Session,应该在所有的 JSP 中关闭它。
  2. Session 何时被删除
    综合前面的讨论,Session 在下列情况下被删除:
  • 程序调用 HttpSession.invalidate();
  • 距离上一次收到客户端发送的 Session id 时间间隔超过了 Session 的超时设置;
  • 服务器进程被停止(非持久 Session)。
  1. 如何做到在浏览器关闭时删除 Session
    严格的讲,做不到这一点。可以做一点努力的办法是在所有的客户端页面里使用 javascript 代码 window.oncolose 来监视浏览器的关闭动作,然后向服务器发送一个请求来删除 Session。但是对于浏览器崩溃或者强行杀死进程这些非常规手段仍然无能为力。
  2. 有个 HttpSessionListener 是怎么回事
    你可以创建这样的 listener 去监控 Session 的创建和销毁事件,使得在发生这样的事件时你可以做一些相应的工作。注意是 Session 的创建和销毁动作触发 listener,而不是相反。类似的与 HttpSession 有关的 listener 还有 HttpSessionBindingListener,HttpSessionActivationListener 和 HttpSessionAttributeListener。
  3. 存放在 Session 中的对象必须是可序列化的吗
    不是必需的。要求对象可序列化只是为了 Session 能够在集群中被复制或者能够持久保存或者在必要时 server 能够暂时把 Session 交换出内存。在 Weblogic Server 的 Session 中放置一个不可序列化的对象在控制台上会收到一个警告。
  4. 开两个浏览器窗口访问应用程序会使用同一个 Session 还是不同的 Session
    对 Session 来说是只认 id 不认人,因此不同的浏览器,不同的窗口打开方式以及不同的 Cookie 存储方式都会对这个问题的答案有影响。
  5. 如何防止用户打开两个浏览器窗口操作导致的 Session 混乱
    这个问题与防止表单多次提交是类似的,可以通过设置客户端的令牌来解决。就是在服务器每次生成一个不同的 id 返回给客户端,同时保存在 Session 里,客户端提交表单时必须把这个 id 也返回服务器,程序首先比较返回的 id 与保存在 Session 里的值是否一致,如果不一致则说明本次操作已经被提交过了。可以参看《J2EE 核心模式》关于表示层模式的部分。需要注意的是对于使用 javascript window.open 打开的窗口,一般不设置这个 id,或者使用单独的 id,以防主窗口无法操作,建议不要再 window.open 打开的窗口里做修改操作,这样就可以不用设置。
  6. 为什么 Session 不见了
    排除 Session 正常失效的因素之外,服务器本身的可能性应该是微乎其微的;理论上防火墙或者代理服务器在 Cookie 处理上也有可能会出现问题。出现这一问题的大部分原因都是程序的错误,最常见的就是在一个应用程序中去访问另外一个应用程序。
  7. 服务器关掉后,当前 Session 会丢掉吗
    这个取决于你使用什么样的 web 服务器以及 web 服务器是如何配置的。tomcat 在 shutdown 前默认会自动将 Session 保存到指定的目录中,重新启动是重新加载,因此 tomcat 重新启动后,Session 是可以继续使用的。此外,你还何以将 Session 保存到数据库中,这个要在 server.xml 中配置。
  8. Cookie 的过期和 Session 的超时有什么区别
    会话的超时由服务器来维护,它不同于 Cookie 的失效日期。首先,会话一般基于驻留内存的 Cookie 不是持续性的 Cookie,因而也就没有截至日期。即使截取到 Jsession Cookie,并为它设定一个失效日期发送出去。浏览器会话和服务器会话也会截然不同。

Session 的用法


Session 对象
可以使用 Session 对象存储特定用户会话所需的信息。这样,当用户在应用程序的 Web 页之间跳转时,存储在 Session 对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。
当用户请求来自应用程序的 Web 页时,如果该用户还没有会话,则 Web 服务器将自动创建一个 Session 对象。当会话过期或被放弃后,服务器将终止该会话。
Session 对象最常见的一个用法就是存储用户的首选项。例如,如果用户指明不喜欢查看图形,就可以将该信息存储在 Session 对象中。
注意:会话状态仅在支持 cookie 的浏览器中保留。
语法
Session.collection|property|method
集合
Contents 包含已用脚本命令添加到会话中的项目。
StaticObjects 包含通过 标记创建的并给定了会话作用域的对象。
属性
CodePage 将用于符号映射的代码页。
LCID 现场标识。
SessionID 返回用户的会话验证。
Timeout 应用程序会话状态的超时时限,以分钟为单位。
方法
Abandon 该方法破坏 Session 对象并释放其资源。
事件
asa 文件中声明下列事件的脚本。
Session_OnEnd
Session_OnStart
注释
您可以在 Session 对象中存储值。存储在 Session 对象中的信息在会话及会话作用域内有效。

  • B3log

    B3log 是一个开源组织,名字来源于“Bulletin Board Blog”缩写,目标是将独立博客与论坛结合,形成一种新的网络社区体验,详细请看 B3log 构思。目前 B3log 已经开源了多款产品:SymSoloVditor思源笔记

    1090 引用 • 3467 回帖 • 297 关注
  • 笔记

    好记性不如烂笔头。

    303 引用 • 777 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...