你的位置:首页 > Java教程

[Java教程]session cookie(li)


Session & Cookie

一、定义

  Session,用户在浏览某个网站时,从进入网站到浏览器关闭所经过的这段时间,也就是用户浏览这个网站所花费的时间。Cookie,由服务器端生成,发送给浏览器,浏览器会将Cookie的key/value保存到某个目录下的文本文件内,下次请求同一网站时就发送该Cookie给服务器(前提是浏览器设置为启用cookie)。

  Session指的是会话,在一次交互的过程中,可以记录住用户的过程,内容保存在服务器端。session判断是否是同一个,需要客户端返回特定id,这个id可以使用cookie实现,也可以使用URL跳转时的附加参数实现。session存在于服务器端,对服务器性能有影响。session用于保存验证信息,cookie用于保存附加信息(个人感觉)。cookie是用于前端和服务器之间的交互,而session可以用于servlet和jsp进行交互。Cookie保存在客户端,有过期时间。cookie通用性会差,客户端可能会禁用,存在安全问题,客户端可以任意查看。

  Cookie可以由用户指定超时时间,Session是保存在服务端,比如Tomcat中Session的默认失效时间为20分钟。Session超时会被清空。虽然Session保存在服务器,对客户端是透明的,它的正常运行仍然需要客户端浏览器的支持。这是因为Session需要使用Cookie作为识别标志。HTTP协议是无状态的,Session不能依据HTTP连接来判断是否为同一客户,因此服务器向客户端浏览器发送一个名为JSESSIONID的Cookie,它的值为该Session的id(也就是HttpSession.getId()的返回值)。Session依据该Cookie来识别是否为同一用户。因此,“若浏览器不支持使用Cookie,或者浏览器设置为不接受Cookie,那么将不能使用Session”,当cookie没了,你存在本地cookie中的session_id也没有了,服务器端没有session_id就找不到session文件,其实session文件还是要等超时以后清空。

二、关系

  1. Cookie和Session都是用来跟踪浏览器用户身份的会话方式。
  2. 位置:Session数据存储在服务器或虚拟服务器端,Cookie数据是存储在客户端的计算机里。
  3. 有效期:Session变量保存在客户端主机的内存上,关闭浏览器或者Session脚本过期后,即自动清除。Cookies保存在客户端主机的硬盘上,可以自行设置Cookies的存在周期,除非设置了临时Cookies,否则关闭浏览器后Cookies信息仍旧保存在主机的硬盘上。
  4. Cookie不是很安全,别人可以分析存放在本地的Cookie并进行Cookie欺骗。
  5. Session对象常用来存储用户的选择项。例如,如果用户指明不喜欢查看图形,就可以将该信息存储在Session对象中.用户的各种私人信息,比如姓名等,某种情况下,需要保存在Session里。用户的其他信息如果需要保留,可以放在Cookie中。
  6. 若浏览器不支持使用Cookie,或者浏览器设置为不接受Cookie,那么将不能使用Session。

三、使用

//session用于保存Http请求之间的状态数据;取得session对象httpSession session = request.getSession();//在session中保存用户状态session.setAttribute("LoginID",myName);//得到myNameString name = (String)session.getAttribute("LoginID");

Session在集群环境中策略:Session对象保存在服务器内存中,由于内存资源有限,也会把一部分Session交换到文件系统中。集群系统中的session:同一个用户的请求可能被分配到不同的机器上执行,如何保证两台服务器中的session一致:

  • 1.session复制,当session有改动时,将复制到其它机器上。
  • 2.广播的方式,服务器之间随时保持同步,缺点是占用带宽较大,网络负担上升。
  • 3.单一数据源,把所有session保存在一个服务器上。
  • 4.TCP-ring方式如何解决session共享问题(在segmentfault中)。

四、Session Store (防止重复提交)

  Session Store使用一组独立的服务器来存放应用运行中需要存储的Object,本质上类似于分布式的Key-Value Store,在KV Store的基础上增加Session命名空间和Session生存周期的管理,如果Session被大量使用,将成为网站应用的核心部件,所以需要Session Store支持持久化存储和基于Multi-Host Data Sync的Failover。在当前网站应用中,为了提高缩放性,所以对Session的使用做了严格的限制,有如下几种方法,这些方法都存在一些缺陷:

  • 避免使用Session,哪怕多查一次DB,这种方法确实比较有效,并且由于现在的应用都使用了Cache服务器,所以正常情况下也不会对DB产生太大的压力,但是不适用于那些不适合存储在DB中的临时状态(例如:计数器,流程状态的指示器等),并且Cache服务器的是通用的,当其他的应用对象太多时,Session数据可能会被清除,导致重复的DB载入动作,对这种场景,我们需要具体分析,把那些访问非常频繁,占用空间不是太大;和一般用的很少,但是每个Session周期中都有几次访问的(这种最容易被LUR算法从cache中清空出去),以及和数据库无关的数据放到Session Store中去。
  • 使用Cookie或者类似于Cookie的方法把Session数据存储在客户端,每次客户提交请求的时候,通过cookie把session重复提交到服务器上,这种方法非常聪明。但是问题也很多,首先是Cookie的大小有严格的限制,不能存放稍微多一点的数据,其次每次来回传输cookie浪费了带宽,和来回解析cookie的CPU资源,最后,session放在客户端会带来安全性问题,客户完全可以通过修改cookie内容来欺骗应用。
  • 使用Memcached来存放Session , 为了防止Session信息被memcached清除,每次访问之后,重复添加新的记录到memcached中,这种方法的缺陷在于,首先,memcached的对象管理不是永久的,session随时可能被换出,意外的crash也会导致session丢失,其次,memcached不是专用的session服务器,所以不能提供session生存周期的管理,Session的创建/清除不太容易控制,最后,memcached不提供方法避免命名空间冲突,需要应用程序端谨慎的避免session key的潜在冲突。
  • 使用UDAS存放Session数据,UDAS的功能类似于Session Store,但是在网站使用的过程中发现有一些,性能,Failover,和高可用性问题,需要在Session Store实现时尽量解决。

五、Java Session

  Session,中文经常翻译为会话,其本来的含义是指有始有终的一系列动作/消息,比如打电话时从拿起电话拨号到挂断电话这中间的一系列过程可以称之为一个session。有时候我们可以看到这样的话“在一个浏览器会话期间,...”,这里的会话一词用的就是其本义,是指从一个浏览器窗口打开到关闭这个期间。最混乱的是“用户(客户端)在一次会话期间”这样一句话,它可能指用户的一系列动作(一般情况下是同某个具体目的相关的一系列动作,比如从登录到选购商品到结账登出这样一个网上购物的过程,有时候也被称为一个transaction),然而有时候也可能仅仅是指一次连接,其中的差别只能靠上下文来推断。

  然而当Session一词与网络协议相关联时,它又往往隐含了“面向连接”和/或“保持状态”这样两个含义,“面向连接”指的是在通信双方在通信之前要先建立一个通信的渠道,比如打电话,直到对方接了电话通信才能开始,与此相对的是写信,在你把信发出去的时候你并不能确认对方的地址是否正确,通信渠道不一定能建立,但对发信人来说,通信已经开始了。“保持状态”则是指通信的一方能够把一系列的消息关联起来,使得消息之间可以互相依赖,比如一个服务员能够认出再次光临的老顾客并且记得上次这个顾客还欠店里一块钱。这一类的例子有“一个TCP session”或者“一个POP3 session。而到了web服务器蓬勃发展的时代,session在web开发语境下的语义又有了新的扩展,它的含义是指一类用来在客户端与服务器之间保持状态的解决方案。有时候session也用来指这种解决方案的存储结构,如“把xxx保存在session里”。由于各种用于web开发的语言在一定程度上都提供了对这种解决方案的支持,所以在某种特定语言的语境下,session也被用来指代该语言的解决方案,比如经常把Java里提供的javax.servlet.http.HttpSession简称为session。

六、HTTP协议与状态保持

  HTTP协议本身是无状态的,这与HTTP协议本来的目的是相符的。客户端只需要简单的向服务器请求下载某些文件,无论是客户端还是服务器都没有必要纪录彼此过去的行为,每一次请求之间都是独立的,好比一个顾客和一个自动售货机或者一个普通的(非会员制)大卖场之间的关系一样。然而聪明(或者贪心?)的人们很快发现如果能够提供一些按需生成的动态信息会使web变得更加有用,就像给有线电视加上点播功能一样。这种需求一方面迫使HTML逐步添加了表单、脚本、DOM等客户端行为,另一方面在服务器端则出现了CGI规范以响应客户端的动态请求,作为传输载体的HTTP协议也添加了文件上载、cookie这些特性。其中cookie的作用就是为了解决HTTP协议无状态的缺陷所作出的努力。至于后来出现的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应用程序开发者造成很大的困扰。