session与cookie

来源:互联网 发布:windows phone 8下载 编辑:程序博客网 时间:2024/05/16 15:20
Session是一种服务器端技术,Session对象在服务器端创建,通常采用散列表来存储信息,例如,Tomcat的Session实现采用HashMap对象来存储属性名和属性值。
Cookie是由Netscape公司发明的、用于跟踪用户会话的一种方式。Cookie是由服务器发送给客户的片段信息,存储在客户端浏览器的内存中或硬盘上,在客户随后对该服务器的请求中发回它。

Session 与Cookie的最大的区别是,Session在服务端保存信息,Cookie在客户端保存信息。为了跟踪用户的会话,服务器端在创建Session后,需要将Session ID交给客户端,在客户端下次请求时,将这个ID随请求一起发送回来。可以采用Cookie或URL重写的方式,将Session ID发送给客户端。


通常,我们将用于会话跟踪的Cookie叫做会话Cookie,在Servlet 规范中,用于会话跟踪的Cookie的名字必须是JSESSIONID,它通常保存在浏览器的内存中。在浏览器内存中的会话Cookie不能被不同的浏览器进程所共享。

session与cookie常见问题与误解

在网络上,很多人有一种错误的认识,认为以不同的方式打开浏览器窗口,或者使用其他的非IE浏览器就可以在不同的浏览器进程之间共享会话 Cookie。分析导致产生错误的原因。

首先看看IE浏览器,启动Tomcat服务器,打开IE浏览器,在地址栏中输入:http://localhost:8080/ch05/login,

然后单击IE浏览器菜单栏上的"文件"→"新建"→"窗口"打开一个新窗口,分别刷新原窗口和新窗口,可以看到两个窗口中显示的Session ID是同一个。由实验可以看到,某些方式下打开的多个IE浏览器,可以共享内存中的Cookie,

而另外一些方式打开的多个IE浏览器,则不能共享内存中的Cookie。再使用其他浏览器进行验证,发现有的浏览器(例如Mozilla FireFox)不管以什么方式打开窗口,都可以共享内存中的Cookie。

由此,一个错误的结论就产生了:不同的浏览器对内存中的Cookie有不同的处理方式,有的浏览器(FireFox)可以在多个浏览器进程间共享会话Cookie,IE浏览器是否共享Cookie,要看浏览器打开的方式。


笔者为什么会说上述结论是错误的呢?这是因为得出结论的人不了解进程的概念。读者在以上述方式打开两个IE浏览器窗口后(如果有其他的IE浏览器打开,请 先关闭),同时按下Ctrl+Alt+Del组合键,选择"任务管理器",切换到"进程"标签页,在"映像名称"下查找IEXPLORE.EXE,看看找 到了几个IEXPLORE.EXE,是不是只有一个!那么这说明了什么?说明我们所看到的两个IE浏览器窗口实际上是属于同一个IE浏览器进程,难怪它们 能共享内存中的会话Cookie。
以其他方式打开一个IE浏览器,可以看到在"映像名称"下多了一个IEXPLORE.EXE进程,既然是两个IE 浏览器进程的窗口,当然无法共享内存中的Cookie了。
同样的道理,Mozilla FireFox不管以什么方式打开窗口,始终只启动了一个进程,既然这些窗口同属于一个进程,当然可以共享内存中的Cookie了。所以我们说,对于存储在内存中的Cookie,是不能被不同的浏览器进程所共享的。共享只能发生在同一个浏览器进程的不同窗口中(因为这些窗口共享同一个进程地址空间)。关于进程和线程的知识,读者可以参看相关的书籍。
对于保存在硬盘上的Cookie,因为是在外部的存储设备中存储,所以可以在多个浏览器进程间共享。

有些人对Session的使用存在着一种误解,认为浏览器一旦关闭,Session就消失了。这是因为有的人看到,关闭浏览器后,再打开一个浏览器,就开始了一次新的会话,从而得出了结论。
之所以会有"浏览器一旦关闭,Session就消失了"这种错误的认识,主要是因为保存Session ID的Cookie是存储在浏览器的内存中,一旦浏览器关闭,Cookie将被删除,Session ID也就丢失了。当再次打开浏览器连接服务器时,服务器没有收到Session ID,当然也就无法找到先前的Session,于是服务器就创建了一个新的Session。而这个时候先前的Session是仍然存在的,直到设置的 Session超时时间间隔发生,Session才被服务器清除。如果我们将会话Cookie保存到硬盘上,或者通过某种技术手段改写浏览器向服务器发送 的请求报头,将原先的Session ID发送给服务器,则再次打开的浏览器就能够找到原来的Session了。

我们想了解一下,用于会话跟踪的Cookie是如何创建的,为何只能保存在浏览器的内存中,而不能保存到用户的硬盘上。在Tomcat 6.0.16.中,Session的创建是调用org.apache.catalina.connector.Request类中的 doGetSession()方法来完成的。下面我们给出这个方法的代码片段:

Java代码
protected Session doGetSession(boolean create)
{

// Creating a new session cookie based on that session
if ((session != null) && (getContext() != null)&& getContext().getCookies())
{
Cookie cookie = new Cookie(Globals.SESSION_COOKIE_NAME,session.getIdInternal());
configureSessionCookie(cookie);
response.addCookieInternal(cookie);
}

if (session != null)
{
session.access();
return (session);
}
else
{
return (null);
}
}

protected void configureSessionCookie(Cookie cookie)
{
cookie.setMaxAge(-1);
String contextPath = null;
if (!connector.getEmptySessionPath() && (getContext() != null))
{
contextPath = getContext().getEncodedPath();
}
if ((contextPath != null) && (contextPath.length() > 0))
{
cookie.setPath(contextPath);
}
else
{
cookie.setPath("/");
}
if (isSecure())
{
cookie.setSecure(true);
}
}


Cookie cookie = new Cookie(Globals.SESSION_COOKIE_NAME,session.getIdInternal()),我们看到非常熟悉的创建Cookie对象的代码,Cookie的名字是Globals.SESSION_ COOKIE_NAME,SESSION_COOKIE_NAME被定义为静态的常量,其值为JSESSIONID。Cookie的值是调用 session.getIdInternal ()得到的Session ID。调用了configureSessionCookie()方法来配置会话Cookie。我们转到 configureSessionCookie()方法中,cookie.setMaxAge(-1),调用Cookie对象的setMaxAge()方 法设置Cookie的生存时间,时间值为负数,那么当客户端的浏览器退出,Cookie将会被删除。看到这儿,我们就知道了为什么会话Cookie只能保 存在内存中了,这是由Tomcat的实现决定的。cookie.setPath(contextPath);调用Cookie对象的setPath()方 法,指定这个Cookie在当前Web应用程序的上下文路径下有效。


session cookie和session对象的生命周期是一样的吗
当用户关闭了浏览器虽然session cookie已经消失,但session对象仍然保存在服务器端


是否只要关闭浏览器,session就消失了
程序一般都是在用户做log off的时候发个指令去删除session,然而浏览器从来不会主动在关闭之前通知服务器它将要被关闭,因此服务器根本不会有机会知道浏览器已经关闭。服务器会一直保留这个会话对象直到它处于非活动状态超过设定的间隔为止。
之所以会有这种错误的认识,是因为大部分session机制都使用会话cookie来保存session id,而关闭浏览器后这个session id就消失了,再次连接到服务器时也就无法找到原来的session。
如果服务器设置的cookie被保存到硬盘上,或者使用某种手段改写浏览器发出的HTTP请求报头,把原来的session id发送到服务器,则再次打开浏览器仍然能够找到原来的session。
恰恰是由于关闭浏览器不会导致session被删除,迫使服务器为session设置了一个失效时间,当距离客户上一次使用session的时间超过了这个失效时间时,服务器就可以认为客户端已经停止了活动,才会把session删除以节省存储空间。
由此我们可以得出如下结论:

关闭浏览器,只会是浏览器端内存里的session cookie消失,但不会使保存在服务器端的session对象消失,同样也不会使已经保存到硬盘上的持久化cookie消失。

要实现关闭浏览器后,在session会话时间内也能取得session信息,只要在程序中取得session id,设置session id的有效期就行

使用下面代码可以实现即使关闭浏览器,也能取到会话期内session信息

HttpSession session = request.getSession();
String id = session.getId();
Cookie cookies[] = request.getCookies();
for(Cookie cookie:cookies){
if(cookie.getName().equals("JSESSIONID")){
Cookie c = new Cookie("JSESSIONID",id);
c.setMaxAge(3600);
response.addCookie(c);
}

}


会话cookie和持久cookie的区别

如果不设置过期时间,则表示这个cookie生命周期为浏览器会话期间,只要关闭浏览器窗口,cookie就消失了。这种生命期为浏览会话期的cookie被称为会话cookie。会话cookie一般不保存在硬盘上而是保存在内存里。如果设置了过期时间,浏览器就会把cookie保存到硬盘 上,关闭后再次打开浏览器,这些cookie依然有效直到超过设定的过期时间。存储在硬盘上的cookie可以在不同的浏览器进程间共享,比如两个IE窗 口。而对于保存在内存的cookie,不同的浏览器有不同的处理方式。


session何时被删除

session在下列情况下被删除:
A.程序调用删除session方法
B.距离上一次收到客户端发送的session id时间间隔超过了session的最大有效时间
C.服务器进程被停止


"实现记住我的登录状态"的功能


前面我们了解到,如果我们将Session ID通过Cookie发送到客户端的时候设置其过期时间为1年,那么在今后的一年时间内,客户端访问我的网站的时候都回将这个Session ID值发送到服务器上,服务器根据这个Session ID从内存或者数据库里面恢复存放Key-Value对的Hashtable。

其实这已经很好的实现了我们的功能了。但是,前面也提到了,实际上Session并不会一直都存在的,过了一定的时间之后,服务器上的Session就被 销毁了,以减轻服务器的访问压力。当服务器上的数据被销毁后,即使客户端上存放了Cookie也没有办法“记住我的登录状态”了。

通用的实现办法是,将用户的用户名和加密之后的密码 也通过Cookie的方式存放在客户端,当服务器上的Session销毁以后,使用Cookie里面存放的用户名和加密之后的密码重新执行一次登录操作, 重建Session,并更新客户端上Cookie中存放的的Session ID,而这个操作是发生在用户请求一个需要身份验证的页面资源的背后,对于用户来讲是透明的,于是就达到了"记住我的登录状态"的目的了
原创粉丝点击