来源:
http://www.iteye.com/topic/960652
http://godsend-jin.iteye.com/blog/1004386
--------------------------------------------------------------------

最近在做登录和权限控制模块,用到了session,发现session的好多方法都不熟悉,而且以前也听说过JsessionId 之类session窃取的事,

对这些一直都是一知半解。今天索性google了很多资料,先上sun的官网去看session的文档了解一些方法,又找了别人关于session的看法。

总结如下:

      1,session是什么?  what

          session经常译为会话,以打电话为例,从开始拨号到挂断电话就是你会话的生存周期。

      2,session 做什么用的  why?

          首先举个例子:

                咖啡店举行 消费满5杯咖啡赠送一杯的活动,可每个人一次消费5杯的时候非常少。这时候有3种办法:

                1,店员看到每个顾客时都能记住其消费了多少杯,从而给其优惠,这是协议本身具有状态

                2,给每个顾客一个卡片,上面记录顾客的每次消费,这是客户端保存状态

                3,给每个顾客一个卡片,卡片上只有一个编号,顾客每次的消费记录在店里,这就是 服务端有状态

          而http本身是无状态的,所以我们只能使用2,3中方法,来保存一些信息。

          实际采用的是第3种方法,服务器段保存一次会话所有的信息,并生成一个唯一的id,这个id没有规律而且不会重复,将这个id传回到客户段,

保存到cookie中。每次访问服务器时,客户端都会偷偷将这个id传到服务器,服务器根据id查到这次会话保存的内容。就能实现会话中共享一些数据。

     3,session怎样创建和销毁 ? how

         session是保存在内存中的,所以会有一些性能上的影响。因此本着这个原则,session是只有在使用到的时候才会被创建,如果始终没有用到

session,这个session是永远不会被创建的。

        比如: 访问servlet ,只要你代码中没有 request.getSession()或request.getSession(true);这两行是等价的,那session是不会创建。

又 当你访问静态页面时,根本不会生成servlet,所以也不会创建session。

       下面解释一些疑惑: session是第一次请求时创建的?

  大家都知道 jsp是被编译成servlet才执行的,问题就在jsp编译的过程。

 jsp中有个<%@ page session="true/false"%> 这个开关表示是否创建session,当你不写这行时,它会默认给你加上这句。所以会造成上面的疑惑。

当然还有一些标签中可能有getSession()操作,会产生一些不必要的session。

       session只能在服务端销毁,有三种途径: 1,到达session的最大请求间隔时间时,2,session。invalidate()

 3,服务器进程当掉。

       这里也有一些疑惑: 浏览器关闭时,session就会注销。

       首先浏览器关闭时,浏览器并没有给服务器发送任何消息,所以服务器不会知道浏览器何时关闭了。

 上面我们知道取得session 是因为浏览器cookie中有sessionid,而普通cookie通常会是会话cookie,也就是说浏览器关闭时,这个cookie会被注销,

所以当你再访问服务器时就没有sessionid了,所以造成session关闭了的假象,如果昵称通过特殊方法将sessionid传递给服务器,你会发现session还在。

如果想让cookie保存时间长一些,就需要手动指定cookie的过期时间

 

4,实际项目中的难点:

     1,浏览器禁用cookie

      这就没办法保存sessionid了,可以采用url重写,转发,加隐藏字段等方法来将sessionid传给服务器。

     如:  baidu.com:jsessionid=adfasdfasdfasdfasdfafdadf?asdfasdf

             baidu.com?jsessionid=asdfasdfasdfadsfad&&adfdf

 这根据服务器的不同实现,第一种可以将普通参数区分开。

 

     2,多人共用session的问题

        例: a 访问 baidu.com ,但他没有帐号,于是他将连接 baidu.com/login.jsp?jsessionid=adsfasdfad(这个a的sessionid) 发给B, B登录

后,a就相当于用b的帐号登录了。你们可以在在本地试试。

        解决方法: 当发现通过sessionid从url指定时, 创建一个新的session,将旧session的信息复制到 新sessoin中,然后将新session注销。

就能防止上面那种情况了。

    3,一个帐号多地方登录

       比如: 你用abc帐号登录了baidu.com,有打开了一个浏览器,又用abc帐号登录了一次。当不设计敏感操作时,这无所谓,而当你做一些敏感操

作时就必须禁止这样情况,防止同时操作,造成重复操作,或者数据损坏。

     解决方法: 监听session,将username和sessionid对应起来,当username再次登录时,注销掉以前的session,保存现在的session,这也是

一种比较不错的方案。

 

这是 sghcel 画的图,挺不错的:

 



其他:
 1session在何时被创建 
    一个常见的误解是以为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在下列情况下被删除a.程序调用HttpSession.invalidate();b.距离上一次收到客户端发送的session id时间间隔超过了session
超时设置
;c.服务器进程被停止(非持久session


    3
、如何做到在浏览器关闭时删除session
Title
  严格的讲,做不到这一点。可以做一点努力的办法是在所有的客户端页面里使用javascript代码window.oncolose来监视浏览器的关闭动作,然后向服务器发送
一个请求来删除
session。但是对于浏览器崩溃或者强行杀死进程这些非常规手段仍然无能为力。


    4
、有个HttpSessionListener是怎么回事 

   
你可以创建这样的listener去监控session的创建和销毁事件,使得在发生这样的事件时你可以做一些相应的工作。注意是session的创建和销毁动作触发listener
而不是相反。类似的与
HttpSession有关的listener还有 HttpSessionBindingListenerHttpSessionActivationListener HttpSessionAttributeListener 

    5
、存放在session中的对象必须是可序列化的吗 


 
不是必需的。要求对象可序列化只是为了session能够在集群中被复制或者能够持久保存或者在必要时server能够暂时把session交换出内存。
Weblogic Serversession中放置一个不可序列化的对象在控制台上会收到一个警告。我所用过的某个iPlanet版本如果session中有不可序列化的对象,
session销毁时会有一个Exception,很奇怪。


    6
、如何才能正确的应付客户端禁止cookie的可能性
 
    对所有的URL使用URL重写,包括超链接,formaction,和重定向的URL,具体做法参见[6]
http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770


    7
、开两个浏览器窗口访问应用程序会使用同一个session还是不同的session 

   
参见第三小节对cookie的讨论,对session来说是只认id不认人,因此不同的浏览器,不同的窗口打开方式以及不同的cookie存储方式都会对这个问题
的答案有影响。
 

    8
、如何防止用户打开两个浏览器窗口操作导致的session混乱 
这个问题与防止表单多次提交是类似的,可以通过设置客户端的令牌来解决。就是在服务器每次生成一个不同的id返回给客户端,同时保存在session里,
客户端提交表单时必须把这个
id也返回服务器,程序首先比较返回的id与保存在session里的值是否一致,如果不一致则说明本次操作已经被提交过了。
可以参看《
J2EE核心模式》关于表示层模式的部分。需要注意的是对于使用javascript window.open打开的窗口,一般不设置这个id,或者使用单独的id
以防主窗口无法操作,建议不要再
window.open打开的窗口里做修改操作,这样就可以不用设置。


    9
、为什么在Weblogic Server中改变session的值后要重新调用一次session.setValue 


做这个动作主要是为了在集群环境中提示Weblogic Server session中的值发生了改变,需要向其他服务器进程复制新的session值。


   10HttpSession 和 hibernate session 有什么区别?
httpSession :

它的产生:J2EE的Web程序在运行的时候,会给每一个新的访问者建立一个HttpSession,这个Session是用户身份的唯一表示。注意,是容器

(Tomcat,Resin)自动创建的。

用途:存放这个用户的一些经常被用到的信息,例如:用户名,权限。例如在购物车程序里,存放用户买的商品。

销毁:一定时间(跟容器有关)内,用户无任何动作,session自动销毁。

得到的方法:
HttpSession session = request.getSession();
常用方法setAttribute
session.setAttribute(key,value);
这样在另一个jsp或者Servlet里,可以用
session.getAttribute(key);得到value
类似一个Map


hibernate session

它是hibernate操作数据库的一个句柄对象。它跟上面那个Session唯一的相似处就是名字有点像,其他没任何一样的地方。
它是hibernate表示操作数据库的一个会话