你会使用session吗?
时间:2007-12-24 来源:fucuihong
具体到Web中的Session指的就是用户在浏览某个网站时,从进入网站到浏览器关闭所经过的这段时间,也就是用户浏览这个网站所花费的时间。因此从上述的定义中我们可以看到,Session实际上是一个特定的时间概念。
需要注意的是,一个Session的概念需要包括特定的客户端,特定的服务器端以及不中断的操作时间。A用户和C服务器建立连接时所处的Session同B用户和C服务器中建立连接时所处的Sessions是两个不同的Session。
那什么是Session的解决方案呢?我们知道,用户访问一个网站时往往需要浏览许多网页。对于一个通过PHP构筑的网站来说,用户在访问的过程中需要执行许多的PHP脚本。然而由于HTTP协议自身的特点,用户每执行一个PHP脚本都需要和Web服务器重新建立连接。
又由于无状态记忆的特点,此次连接无法得到上次连接的状态。这样,用户在一个PHP脚本中对一个变量进行了赋值操作,而在另外一个PHP脚本中却无法得到这个变量的值。例如,用户在负责登录的PHP脚本中设置了$user="wind",却无法在另一个PHP脚本中通过调用$user来获得“wind”这个值。也就是说,在PHP中无法设置全局变量。每个PHP脚本中所定义的变量都是只在这个脚本内有效的局部变量。
Session解决方案,就是要提供在PHP脚本中定义全局变量的方法,使得这个全局变量在同一个Session中对于所有的PHP脚本都有效。上面我们提到了,Session不是一个简单的时间概念,一个Session中还包括了特定的用户和服务器。因此更详细地讲,在一个Session定义的全局变量的作用范围,是指这个Session所对应的用户所访问的所有PHP。
例如A用户通过Session定义了一个全局变量$user=“wind”中,而B用户通过Session定义的全局变量$user=“jane”。那么在A用户所访问的PHP脚本中,$user的值就是wind。
在ASP 和 ASP.NET 中
Session 是 用于保持状态的基于 Web 服务器的方法。Session 允许通过将对象存储在 Web 服务器的内存中在整个用户会话过程中保持任何对象。
Session 通常用于执行以下操作:
存储需要在整个用户会话过程中保持其状态的信息,例如登录信息或用户浏览 Web 应用程序时需要的其它信息。
存储只需要在页重新加载过程中或按功能分组的一组页之间保持其状态的对象。
Session 的作用就是它在 Web 服务器上保持用户的状态信息供在任何时间从任何页访问。因为浏览器不需要存储任何这种信息,所以可以使用任何浏览器,即使是像 PDA 或手机这样的浏览器设备。
此持久性方法的限制
随着越来越多用户登录,Session 所需要的服务器内存量也会不断增加。
访问 Web 应用程序的每个用户都生成一个单独的 Session 对象。每个 Session 对象的持续时间是用户访问的时间加上不活动的时间。
如果每个 Session 中保持许多对象,并且许多用户同时使用 Web 应用程序(创建许多 Session),则用于 Session 持久性的服务器内存量可能会很大,从而影响了可伸缩性。 IE中:
有效的窗品包括
1.Session对象只在建立Session对象的窗口中有效。
2.在建立Session对象的窗口中新开链接的窗口
无效的窗口包括
1.直接启动IE浏览器的窗口
2.不是在建立Session对象的窗口中新开链接的窗口
NetScape中:
只要一个窗口有了某个Session对象,则全部窗口对此Session都有效
Session是什么呢?简单来说就是服务器给客户端的一个编号。当一台WWW服务器运行时,可能有若干个用户浏览正在运正在这台服务器上的网站。当每个用户首次与这台WWW服务器建立连接时,他就与这个服务器建立了一个Session,同时服务器会自动为其分配一个SessionID,用以标识这个用户的唯一身份。这个SessionID是由WWW服务器随机产生的一个由24个字符组成的字符串,我们会在下面的实验中见到它的实际样子。
这个唯一的SessionID是有很大的实际意义的。当一个用户提交了表单时,浏览器会将用户的SessionID自动附加在HTTP头信息中,(这是浏览器的自动功能,用户不会察觉到),当服务器处理完这个表单后,将结果返回给SessionID所对应的用户。试想,如果没有SessionID,当有两个用户同时进行注册时,服务器怎样才能知道到底是哪个用户提交了哪个表单呢。当然,SessionID还有很多其他的作用,我们会在后面提及到。
除了SessionID,在每个Session中还包含很多其他信息。但是对于编写ASP或ASP.NET的程序与来说,最有用的还是可以通过访问ASP/ASP.NET的内置Session对象,为每个用户存储各自的信息。例如我们想了解一下访问我们网站的用户浏览了几个页面,我们可能在用户可能访问到每个的页面中加入:
<%
If Session("PageViewed") = ""Then
Session("PageViewed") = 1
Else
Session("PageViewed") = Session("PageViewed") + 1
End If
%>
通过以下这句话可以让用户得知自己浏览了几个页面:
<%
Response.Write("You have viewed " & Session("PageViewed") & " pages")
%>
可能有些有些读者会问:这个看似像是数组的Session(“..”)是哪里来的?需要我定义吗?实际上,这个Session对象是具有ASP解释能力的的WWW服务器的内建对象。也就是说ASP的系统中已经给你定义好了这个对象,你只需要使用就行了。其中Session(“..”)中的..就好像变量名称,Session(“..”)=$$中的$$就是变量的值了。你只需要写上句话,在这个用户的每个页面中都可以访问..变量中的值了。
其实ASP一共内建了7个对象,有Session、Application、Cookie、Response、Request、Server等。在其他的服务器端脚本语言如JSP、PHP等中也有其类似的对象,只是叫法或者使用方法上不太一样。
ASP Session的功能的缺陷
目前ASP的开发人员都正在使用Session这一强大的功能,但是在他们使用的过程中却发现了ASP Session有以下缺陷:
进程依赖性:ASP Session状态存于IIS的进程中,也就是inetinfo.exe这个程序。所以当inetinfo.exe进程崩溃时,这些信息也就丢失。另外,重起或者关闭IIS服务都会造成信息的丢失。
Session状态使用范围的局限性:刚一个用户从一个网站访问到另外一个网站时,这些Session信息并不会随之迁移过去。例如:新浪网站的WWW服务器可能不止一个,一个用户登录之后要去各个频道浏览,但是每个频道都在不同的服务器上,如果想在这些WWW服务器共享Session信息怎么办呢?
Cookie的依赖性:实际上客户端的Session信息是存储与Cookie中的,如果客户端完全禁用掉了Cookie功能,他也就不能享受到了Session提供的功能了。
鉴于ASP Session的以上缺陷,微软的设计者们在设计开发 ASP.NET Session时进行了相应的改进,完全克服了以上缺陷,使得ASP.NET Session成为了一个更加强大的功能。
Session模型简介
Session是什么呢?简单来说就是服务器给客户端的一个编号。当一台WWW服务器运行时,可能有若干个用户浏览正在运正在这台服务器上的网站。当每个用户首次与这台WWW服务器建立连接时,他就与这个服务器建立了一个Session,同时服务器会自动为其分配一个SessionID,用以标识这个用户的唯一身份。这个SessionID是由WWW服务器随机产生的一个由24个字符组成的字符串,我们会在下面的实验中见到它的实际样子。
这个唯一的SessionID是有很大的实际意义的。当一个用户提交了表单时,浏览器会将用户的SessionID自动附加在HTTP头信息中,(这是浏览器的自动功能,用户不会察觉到),当服务器处理完这个表单后,将结果返回给SessionID所对应的用户。试想,如果没有SessionID,当有两个用户同时进行注册时,服务器怎样才能知道到底是哪个用户提交了哪个表单呢。当然,SessionID还有很多其他的作用,我们会在后面提及到。
除了SessionID,在每个Session中还包含很多其他信息。但是对于编写ASP或ASP.NET的程序与来说,最有用的还是可以通过访问ASP/ASP.NET的内置Session对象,为每个用户存储各自的信息。例如我们想了解一下访问我们网站的用户浏览了几个页面,我们可能在用户可能访问到每个的页面中加入:
<% If Session(PageViewed) = Then Session(PageViewed) = 1 Else Session(PageViewed) = Session(PageViewed) + 1 End If %>
通过以下这句话可以让用户得知自己浏览了几个页面:
<% Response.Write(You have viewed & Session(PageViewed) & pages) %>
可能有些有些读者会问:这个看似像是数组的Session(“..”)是哪里来的?需要我定义吗?实际上,这个Session对象是具有ASP解释能力的的WWW服务器的内建对象。也就是说ASP的系统中已经给你定义好了这个对象,你只需要使用就行了。其中Session(“..”)中的..就好像变量名称,Session(“..”)=$$$中的$$$就是变量的值了。你只需要写上句话,在这个用户的每个页面中都可以访问..变量中的值了。
其实ASP一共内建了7个对象,有Session、Application、Cookie、Response、Request、Server等。在其他的服务器端脚本语言如JSP、PHP等中也有其类似的对象,只是叫法或者使用方法上不太一样。
ASP Session的功能的缺陷
目前ASP的开发人员都正在使用Session这一强大的功能,但是在他们使用的过程中却发现了ASP Session有以下缺陷:
进程依赖性:ASP Session状态存于IIS的进程中,也就是inetinfo.exe这个程序。所以当inetinfo.exe进程崩溃时,这些信息也就丢失。另外,重起或者关闭IIS服务都会造成信息的丢失。
Session状态使用范围的局限性:刚一个用户从一个网站访问到另外一个网站时,这些Session信息并不会随之迁移过去。例如:新浪网站的WWW服务器可能不止一个,一个用户登录之后要去各个频道浏览,但是每个频道都在不同的服务器上,如果想在这些WWW服务器共享Session信息怎么办呢?
Cookie的依赖性:实际上客户端的Session信息是存储与Cookie中的,如果客户端完全禁用掉了Cookie功能,他也就不能享受到了Session提供的功能了。
鉴于ASP Session的以上缺陷,微软的设计者们在设计开发 ASP.NET Session时进行了相应的改进,完全克服了以上缺陷,使得ASP.NET Session成为了一个更加强大的功能。
Web.config文件简介
有的ASP.NET程序员说:Web.config文件?我从来没有听说过啊,可是我写的程序不是也能很正常的运转吗?是的,你说得没错,没有Web.config文件程序是可以正常运行的。但是,如果你做了一个大型的网站,需要对整个网站做一些整体配置,例如整个网站的页面使用何种语言编写的、网站的安全认证模式、Session信息存储方式等,这时你就需要使用Web.config文件了。虽然Web.config文件中的某些选项是可以通过IIS配置的,但是如果在Web.config中也有相应的设置就会覆盖掉IIS中的配置。而且,Web.config文件的最大的便利之处就是可以在ASP.NET页面中通过调用System.web名字空间访问Web.config中的设置。
Web.config有两种,分别是服务器配置文件和Web应用程序配置文件,他们都名为Web.config。在这个配置文件中会保存当前IIS服务器中网页的使用哪种语言编写的、应用程序安全认证模式、Session信息存储方式的一系列信息。这些信息是使用XML语法保存的,如果想对其编辑,使用文本编辑器就行了。
其中服务器配置文件会对IIS服务器下所有的站点中的所有应用程序起作用。在.NET Framework 1.0中,服务器的Web.config文件是存在:\WinNT\Microsoft.NET\Framework\v1.0.3705中的。
而Web应用程序配置文件Web.config则保存在各个Web应用程序中。例如:当前网站的根目录\Inetpub\wwwroot,而当前的Web应用程序为MyApplication,则Web应用程序根目录就应为:\Inetpub\wwwroot\MyApplication。如果你的网站有且只有一个Web应用程序,一般说来应用程序的根目录就是\Inetpub\wwwroot。如果想添加一个Web应用程序,在IIS中添加一个具有应用程序起始点的虚拟目录就行了。这个目录下的文件及目录将被视为一个Web应用程序。但是,这样通过IIS添加Web应用程序是不会为你生成Web.config文件的。如果想创建一个带有Web.config文件的Web应用程序,需要使用Visual Studio.NET,新建一个Web应用程序项目。
Web应用程序的配置文件Web.config是可选的,可有可无。如果没有,每个Web应用程序会使用服务器的Web.config配置文件。如果有,则会覆盖服务器Web.config配置文件中相应的值。
在ASP.NET中,Web.config修改保存后会自动立刻成效,不用再像ASP中的配置文件修改后需要重新启动Web应用程序才能生效了。
Web.config文件中的Session配置信息
打开某个应用程序的配置文件Web.config后,我们会发现以下这段:
< sessionState mode =InProc stateConnectionString =tcpip=127.0.0.1:42424 sqlConnectionString =data source=127.0.0.1;Trusted_Connection=yes cookieless =false timeout =20 / >
这一段就是配置应用程序是如何存储Session信息的了。我们以下的各种操作主要是针对这一段配置展开。让我们先看看这一段配置中所包含的内容的意思。sessionState节点的语法是这样的:
<sessionState mode = Off|InProc|StateServer|SQLServer
cookieless = true|false
timeout = number of minutes
stateConnectionString = tcpip=server:port
sqlConnectionString = sql connection string
stateNetworkTimeout= number of seconds
/>
必须有的属性是
属性
选项
描述
mode
设置将Session信息存储到哪里
Off
设置为不使用Session功能
InProc
设置为将Session存储在进程内,就是ASP中的存储方式,这是默认值。
StateServer
设置为将Session存储在独立的状态服务中。
SQLServer
设置将Session存储在SQL Server中。
可选的属性是:
属性
选项
描述
cookieless
设置客户端的Session信息存储到哪里
ture
使用Cookieless模式
false
使用Cookie模式,这是默认值。
timeout
设置经过多少分钟后服务器自动放弃Session信息。默认为20分钟
stateConnectionString
设置将Session信息存储在状态服务中时使用的服务器名称和端口号,例如:tcpip=127.0.0.1:42424”。当 mode 的值是 StateServer 是,这个属性是必需的。
sqlConnectionString
设置与SQL Server连接时的连接字符串。例如data source=localhost;Integrated Security=SSPI;Initial Catalog=northwind。当 mode 的值是 SQLServer 时,这个属性是必需的。
stateNetworkTimeout
设置当使用StateServer模式存储Session状态时,经过多少秒空闲后,断开Web服务器与存储状态信息的服务器的TCP/IP连接的。默认值是10秒钟。
ASP.NET中客户端Session状态的存储
在我们上面的Session模型简介中,大家可以发现Session状态应该存储在两个地方,分别是客户端和服务器端。客户端只负责保存相应网站的SessionID
写过稍微大型一点 ASP 的人都知道,Session 这个对象真是好用,它可以用来记录使用者私有的资料变量,既安全又方便。但是你真的知道 Session 的运作原理吗?或许了解以后,你就再也不太敢使用这个令人又爱又恨的对象。虽然转而替代之的方法稍嫌麻烦,但在长期考量之下,也就不得不这么做了。
首先来讲讲 Session 的好处,它可以用来记录客户端私有的资料变量,并且在时间范围内不会消失。这真的是很重要的功能,尤其是有会员的系统必须要用到的。像是会员的登入帐号、时间、状态以及许许多多该记录的实时数据﹝如购物系统记录使用者的购物篮内的商品﹞,这些信息属于各使用者私人所需要,通常开发者都是使用 Session 记录处理。
然而,在 ASP 中的 Session 是使用 Cookies 所构成,服务器将所有的 Session 内记录的资料,以 Cookies 的方式传至用户的浏览器。通常一般浏览器会将这些 Cookies 存起来,每当使用者点选连结,再次与服务器做联机时,浏览器就会把这些 Cookies 传回 Server 供做处理。这即是 Session 的运作原理,当资料量大一点时,由于必须传出去又收回来,不但吃线路频宽,效能相对降低,因为 Server 必须花费更多的资源在做联机处理和重新配置内存等初始动作。现在你可能会想『我必须用这功能,只好牺牲点了』,不过本文讲 Session 一方面是教导大家少用;另一方面当然是有替代办法,紧接着上场的,就是同属 Global.asa 内的 Application 对象。
Application 也是记录处理暂时资料的好手,各方面的能力和用法都和 Session 一样,只不过相较之下,它所记录的资料是属于公用的,也就是任何使用者都可以共享的变量空间。Application 不像 Session ,不是将资料传给使用者,等下一次联机再读取回来,它是直接记录在 Server 上的内存,相对之下效能上快上 Session 许多。
由于 Application 对象是公用的,首先必须做的,就是要把一块公用的区域规划给各个使用者,让每个用户拥有自己的区域可以记录资料,以达到仿真 Session 的目的。现在有两种做法:
一、在 Server 激活时事先初始化建立及分配使用者内存空间,通常这种做法虽然一 Server 开机就先占了许多资源,但也省去了以后每当使用者联机就必须做一次分配的麻烦。但有个限制,使用这种方法必须限制最大人数,由于是一激活就初始化,我们只能预估建立某数量的内存空间,所以这种方法通常用于聊天室这种小型的程序上。
二、这种方法对于大型应用程序来说应该算较恰当的,采用动态的分配法,当使用者第一次联机到 Server 上才开始分配资源给此用户。这两种仿真 Session 的方案,目的都是减轻 Session 资源的消耗,但毕竟还是无法完全替代,我们还是需要使用到一点点 Session,至少对 Server 已经能减轻不少负担了。
■第一方案
首先我们开始第一个方案的实作,由于是激活时初始化 Application,我们当然要从 Global.asa中着手:
已经完成初始化了,但如何使用呢?我们只要在使用者登入的地方,把原本使用 Session 储存的资料,如帐号、登入时间,改成我们建立好的 Application 对象中就可以了:
'寻找未被使用的空间
For i = 1 To Application("ClientMax")
If Application("User_Status_" & i) = 0 Then
'使用者暂时编号
Session("Index") = i
'锁定
Application Application.Lock
'设成已使用的状态
Application("User_Status_" & i) = 1 '放入变量数据
Application("User_Account_" & i) = Account
Application("User_Logtime_" & i) = Now()
'解除锁定
Application.Unlock
Exit For
End If
Next
要取得使用者的相关变量数据则就像下面的做法:
Response.Write(Application("User_Account_" & Session("Index"))
你可能会发现,不是说不要使用 Session 吗?那为什么上面的原始码中还有 Session 的存在?前面也说过,这替代方案并不能完全代替掉 Session,浏览器并不是一直和 Server 处于联机状态的,读取完页面就断线,那我们要怎么知道下次联机的还是同一个人呢?这时候就必须要靠 Session,我们给使用者一组实时的编号,此编号就是使用者于 Application 上变量空间的号码,你可以想象成银行中有很多的保险箱,你拥有一支钥匙,而钥匙上有编号,钥匙上的编号可以让行员带领你去你自己的保险箱。此方法尚还有改进之处,但对小型的应用程序已经是很够用了。
■第二方案
关于上一方案,你可能也想到,我们自订的编号使用了 Session 来记录,讲到编号,Session 对象有提供一个『 SessionID 』方法。没错,不管我们要不要使用,Server 都会自动帮每个用户编列号码,且此号码不会重复,至于这号码就是用 Session.SessionID 取得。这编列号码是 Session 一定会做的动作,我们就可利用它代替我们自己写的编号程序,亦又省了一道功夫,甚至有更大的扩充性。但基本上,上面的第一个方案还是有它的用途在,像是会限制人数的聊天室等等小应用程序,接下来的第二替代方案,就是针对较大型的系统了。
每秒上站人数达数百数千甚至上万人的网站,使用之前的方案,必定是行不通的。假设你将上限人数设 10000 ,Server 一激活就会帮你切出一万个区域准备给一万个使用者,假若一个区域中有 5 个变量,一个变量占 32 字节(Byte),10000 个就占了 320000 K(320MB) 以上,Server 一激活就塞了那么多的垃圾到内存,效能势必还没上战场就降低不少;而且别看这些数字很少,以为自己的 512 MB 会够用,上面的数字是假设一个最低数字,加上 Server 在配置内存时会额外使用到多少资源不得而知,所以只会更多不会更低。因此解决办法只有动态配置使用者变量空间,当有使用者与 Server 联机时才切一块区域出来,如此便不须要事先就配置好庞大内存。
第二方案做起来是比较简单,请把第一方案的东西全部丢掉,我们不需要动到 Global.asa,只需要改使用者登入的地方和其它有用到的地方:
'锁定 ApplicationApplication.Lock '放入变量数据
Application("User_Account_" & Session.SessionID) = Account
Application("User_Logtime_" & Session.SessionID) = Now() '解除锁定Application.Unlock
要取得使用者的相关变量数据则就像下面的做法:
Response.Write(Application("User_Account_" & Session.SessionID))
以往看很多书,都写着 Session 吃资源吃的很凶,尽量不要用,可是必须用的时候还是得用,书里又都没教较妥当的解决办法。现在当你懂了如何替代 Session,好好去利用吧!或许老是困扰的效能问题能因此改善不少!