[Asp.Net]状态管理(ViewState、Cookie)

时间:2023-03-21 22:45:24

简介

HTTP协议是无状态的。从客户端到服务器的连接可以在每个请求之后关闭。但是一般需要把一些客户端信息从一个页面传送给另一个页面。

  • 无状态的根本原因是:浏览器和服务器使用Socket通信,服务器将请求结果返回给浏览器后,会关闭当前Socket连接。而且服务器会在处理页面完毕后销毁页面对象。
  • 应用层面的原因是:浏览器和服务器之间通信都遵守HTTP协议。
  • Http协议是无状态的,不会记得上次和网页“发生了什么。服务器不记得上次给了浏览器什么。
  • 对网站造成的影响:如果用户录入了一些信息,当跳转到下一个页面时,数据丢失,再也不能获得那些数据。

如果要知道上一次的状态信息,我们就得把这个状态信息记录在某个地方:

a.服务器端

b.浏览器端(客户端)

c. 表单元素中—如:隐藏域<input type=“hidden”/>(Http报文)

在保存状态的各种方式中,主要区别是:状态是存储在客户端还是服务器上,下表列出了各种状态管理技术以及状态保持有效的时间。

状态类型 客户端或服务器资源 有效时间
ViewState 客户端 只在一个页面中
Cookie 客户端 关闭浏览器时会删除临时cookie(此时的cookie没有设置有效时间,存储在浏览器内存中,关闭浏览器cookie自动删除),永久存储在用户系统磁盘上。
Session 服务器 回话状态与浏览器回话相关。回话在超时后无效(默认为20分钟)
Application 服务器 应用程序状态在所有的客户端上共享,这个状态在服务器重启之前都是有效的
Cache 服务器 类似于应用程序状态,高速缓存是共享的。但是,使高速缓存无效有更好的控制方式

先将状态管理的五种方式基本概念放在一起,方便比较记忆。

网络上有一种划分更细的方案,如下图所示:

[Asp.Net]状态管理(ViewState、Cookie)

客户端的状态保持方案:ViewState、隐藏域、Cookies、控件状态、URL查询参数

服务端的状态保持方案:Session(会话)、Application、Caching(缓存)、DataBase(数据库)

客户端的状态管理

  1. ViewState

关于ViewState讲的太多了,我这里也是将需注意的地方写下来,方便日后查询,当然也希望能帮到别人。Web服务器控件自动使用ViewState来使事件工作。ViewState包含的状态与控件发送给客户端时所包含的状态相同。当浏览器把窗体发送给服务器时,ViewState包含了初始值,但所发送的控件包含新值。如果初始值和新值有区别,就调用相应的时间处理程序。

使用ViewState的缺点是。数据总是要从服务器传送给客户端,再从客户端传送给服务器,增加了网络流量。为了减少网络流量,可以关闭ViewState。在Page指令中把EnableViewState属性设置为false,就可以关闭页面中所有控件的ViewState。

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="Wolfy.WebChat.Server.Default" EnableViewState=" false" %>

设置一个控件的EnableViewState属性,也可以配置该控件的ViewState。无论页面进行了什么配置,只要定义了控件的EnableViewState属性,就使用控件配置的值(优先级较高),只有没有配置ViewState的控件才使用页面配置的值。
       还可以把定制的数据存储在ViewState中。为此可以使用索引符和page类的ViewState属性。可以设置Index参数定义一个名称,用于访问ViewState值。

ViewState["mydata"] = "中秋节快乐";

可以读取前面存储的ViewState,如下所示:

  string mydata = (string)ViewState["mydata"];

在发送给客户端的HTML代码中,整个页面的ViewState存储在一个隐藏域中:

<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="pRdkV9UzTFimveKGNXH7EJyJbDjTrumX55ovGtz5zcgHVPI4HrWrE+I81Ox6/Pb8mOi2UVpNLkMyuEpl5Zj6UQQwwJpxpHbUpZbe2TkcyAJnmLda+oPgf/vO+rmInjm1" />

使用隐藏域的优点是,每个浏览器都可以使用这个特性,用户不能关闭它。

ViewState只保存在页面中。如果状态应保存在多个不同的页面中,就应使用cookie在客户端保存状态。

总结:

默认情况下,ViewState是被启用的,比如提交表单后,表单中输入的值会自动保留。但是如果不需要保留,也可以将其禁用,这样可以节省资源。

    • 服务器在接收到用户请求一个页面后,会自动在请求报文中找看是否包含__VIEWSTATE的隐藏域,如果有,则将中间的值解码后添加到页面的ViewState属性中。
    • 服务器在输出的时候,也会自动的将ViewState中的值添加到表单里名叫__VIEWSTATE的隐藏域中
    • VIEWSTATE适用于同一个页面在不关闭的情况下多次与服务器交互

下面3种方式就可以分别禁用某一个控件、某一个页面和整个应用程序的ViewState。
            1) 控件禁用:将控件的EnableViewState属性设置为false;

2) 页面禁用:在页面的Page指令中添加EnableViewState="false";

3) 应用程序禁用:在Web.Config文件中添加

<configuration>
<system.web>
<pages enableViewState="false"></pages>
</system.web>
</configuration>

2. Cookie

cookie在HTTP头中定义。使用HttpResponse类可以把cookie发送给客户端。Response是Page类的一个属性,它返回一个HttpResponse类型的对象。HttpResponse类定义了返回HttpCookieColletion的Cookies属性。使用HttpCookieColletion可以向客户端返回多个cookie。

下面的实例代码说明了如何把cookie发送给客户端。首先,实例化一个HttpCookie对象。在这个类的构造函数中,设置cookie的名称,这里是mycookie。HttpCookie类的Values属性可以添加多个cookie值。如果只返回一个cookie的值,就可以使用Value属性。但如果要发送多个cookie值,最好把值添加到一个cookie中,而不是使用多个cookie。

             string myval = "myval";
HttpCookie cookie = new HttpCookie("mycookie");
cookie.Values.Add("mystate", myval);
Response.Cookies.Add(cookie);

cookie可以是临时的,仅在一个浏览器回话中有效,也可以存储在客户端的磁盘上。为了使cookie变成永久的,必须使用HttpCookie对象设置Expires属性。使用Expires属性可以定义cookie不再有效的日期,这里把它设置为三个月后。
     尽管可以设置特定的日期,但不能保证cookie会存储到该日期位置。用户可以删除cookie,如果在本地存储了太多的cookie,浏览器应用程序也可能删除它,浏览器只能为每个服务器存储20个cookie,为所有的服务器存储300个cookie(根据各浏览器而定)。达到极限后,就删除有一段时间已不再使用的cookie。

             string myval = "myval";
HttpCookie cookie = new HttpCookie("mycookie");
cookie.Values.Add("mystate", myval);
cookie.Expires = DateTime.Now.AddMonths();
Response.Cookies.Add(cookie);

客户端从服务器上请求一个页面时,这个服务器的cookie就可以在客户端上使用,并作为http请求的一部分发送给服务器。要在Asp.Net页面中读取cookie,可以访问HttpRequest对象中的cookie集合。
       与Http响应一样,Page类也有一个Request属性返回HttpRequest类型的对象。Cookies属性返回HttpCookieCollection,它可以用于读取客户端发送的cookie。可以用索引符通过其名来访问cookies,然后使用HttpCookie的Values属性从cookie中获取值。

            HttpCookie cookie = Request.Cookies["mycookie"];
string myval = cookie.Values["mystate"];

Asp.Net很容易使用cookie。但必须了解cookie的限制。如前所述,浏览器只能接收来自一个服务器的20个cookie,以及来自所有服务器的300个cookie。另外,cookie的大小也有限制。cookie不能存储多余4K的数据。这些限制的存在使客户端磁盘不会被cookie占满。

Cookie原理:cookie是如何往返的?

[Asp.Net]状态管理(ViewState、Cookie)

* 服务器向浏览器写出Cookie实际上就是在 响应报文中 生成响应行:

* Set-Cookie: uinfo2=123; expires=Mon, 06-Jun-2011 06:48:47 GMT; path=/

* 浏览器读取此 响应行后 会自动在客户端硬盘中产生一个Cookie文件,名为:

* Cookie:administrator@localhost/,注意@后的 localhoust/ ,实际上是颁发此Cookie网站的域名;

* 当浏览器下次再访问此域名时,就会自动将 后缀为 localhoust/ 的cookie文件内容发送到服务器。

补充:

不同浏览器间cookie总大小也不同:

Firefox和Safari允许cookie多达4097个字节,包括名(name)、值(value)和等号。

Opera允许cookie多达4096个字节,包括:名(name)、值(value)和等号。

InternetExplorer允许cookie多达4095个字节,包括:名(name)、值(value)和等号。

浏览器允许每个域名所包含的cookie数:

Microsoft指出InternetExplorer8增加cookie限制为每个域名50个,但IE7似乎也允许每个域名50个cookie。

Firefox每个域名cookie限制为50个。

Opera每个域名cookie限制为30个。

Safari/WebKit貌似没有cookie限制。但是如果cookie很多,则会使header大小超过服务器的处理的限制,会导致错误发生。

注:“每个域名cookie限制为20个”将不再正确!

当很多的cookie被设置,浏览器如何去响应。

除Safari(可以设置全部cookie,不管数量多少),有两个方法:

最少最近使用(leastrecentlyused(LRU))的方法:当Cookie已达到限额,自动踢除最老的Cookie,以使给最新的Cookie一些空间。InternetExplorer和Opera使用此方法。

Firefox很独特:虽然最后的设置的Cookie始终保留,但似乎随机决定哪些cookie被保留。似乎没有任何计划(建议:在Firefox中不要超过Cookie限制)。