Cookies使用

本文介绍了ASP.NET中使用Cookie的基本概念和技术,包括如何在ASP.NET Web应用程序中读取和写入HTTP Cookie,以及Cookie的限制、安全性等方面的知识。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ASP.NET 中使用 Cookie 的基本概念
 
 
 
摘要: 说明如何使用 c# ASP.NET Web 应用程序中读取和写入 HTTP Cookie
适用于
·                  ASP.NET
·                  Microsoft® Visual Studio® .NET
·                  Web 窗体
适合程度: Web 程序开发初学者
目录
简介
Cookie 是在 Web 应用程序中提供储存使用者特定信息的有用方法。例如,当使用者造访网站时,您可以使用 Cookie 来储存使用者偏好设定或其它信息。当使用者下次造访您的网站时,应用程序可以撷取先前储存的信息。
本文提供在 ASP.NET 应用程序中使用 Cookie 的概观。我将说明在 ASP.NET 应用程序中使用 Cookie 的技巧,例如撰写 Cookie 并于稍后再读取。同时,我将说明 Cookie 的各种功能和特性,以及 ASP.NET Cookie 的支援。
何谓 Cookie
Cookie 是伴随使用者要求和网页在 Web 服务器和浏览器之间传送的小段文字。 Cookie 包含 Web 应用程序在使用者造访网站时可读取的信息。
想象当使用者由网站 (www.contoso.com) 要求网页时,您的应用程序不只传送网页,还有包含日期和时间的 Cookie 。当使用者的浏览器取得网页时,浏览器也会取得储存在使用者硬盘中某数据夹内的 Cookie
稍后,使用者再次由网站要求网页。当使用者输入 URL www.contoso.com 时,浏览器会在本机硬盘中寻找该 URL 相关联的 Cookie 。如果有这个 Cookie ,浏览器就会将 Cookie 随着网页要求一起传送至您的网站。然后您的应用程序可决定该使用者上次造访网站的日期和时间。您可以使用此信息对使用者显示讯息、检查到期时间或执行任何其它有用的功能。
Cookie 与网站相关联,并非关联特定网页,因此浏览器和服务器会交换 www.contoso.com Cookie 信息,不论使用者由网站要求哪个网页,浏览器和服务器都会交换 www.contoso.com Cookie 信息。当使用者造访不同的网站时,每一个网站都可能传送 Cookie 给使用者的浏览器,浏览器会分别储存所有的 Cookie
这就是 Cookie 运作的基本方式。但是它们有何好处呢?基本上, Cookie 可协助网站储存访客的相关信息。广义来说, Cookie 是维持 Web 应用程序连续性的一种方法 ( 正确来说是执行「状态管理」 ) 。除了实际交换信息的短暂时间之外,浏览器和 Web 服务器并未联机。您对 Web 服务器所做的每一个要求都与其它要求分开处理。不过,许多时候在您要求网页时,让 Web 服务器能辨识您的身份非常有用。例如,购物网站的 Web 服务器可用来追踪各个购物者,让网站可以管理购物车和其它使用者特定信息。因此 Cookie 的作用类似电话卡,可显示适当的识别信息,以协助应用程序继续执行。
Cookie 有各种用途,其目的均在协助网站记住您的相关信息。例如,执行民意调查的网站可能只是使用 Cookie 作为布尔值,指出您的浏览器是否已经参与投票,让您不会重复投票。需要您登入的网站可能使用 Cookie 来告诉它您已经登入,因此您不必重复输入认证信息。
如需更多有关 Cookie 的背景信息,建议您参阅 http://www22.verizon.com/about/community/learningcenter/articles/displayarticle1/0,4065,1022z1,00.html Verizon 网站中的 How Internet Cookies Work ( 英文 ) 。作者说明了有关何谓 Cookie 及浏览器和服务器之间如何交换 Cookie 的详细信息。其中还包括关于 Cookie 涉及的隐私权问题摘要。
附带一提,您可曾想过它们为何叫做 Cookie 吗? Jargon File ( 又称为 The New Hacker's Dictionary) 版本 4.3.3 中有很好的定义,并对其来源提出合理的解释。您可以在 http://www.catb.org/~esr/jargon/jargon.html#cookie 中找到这个字。
从这里开始,我将假设您了解何谓 Cookie ,以及为何要在 ASP.NET 应用程序中使用 Cookie
Cookie 限制
在开始说明使用 Cookie 的技巧之前,我想先提出几点相关的限制。大多数的浏览器都支持可达 4096 个字节的 Cookie 。这个大小对于在使用者的计算机中储存一些值已经很够,但是请勿在 Cookie 中储存数据集或其它有可能很占空间的数据。更实际来说,不要在 Cookie 中储存大量的使用者信息。而是要储存使用者编号或其它识别码。然后,当使用者再度造访网站时,您就可以用使用者 ID 来查询数据库中使用者的详细数据 ( 但是,有关储存使用者信息的详细信息,请参阅本文 Cookie 和安全性)
浏览器也会对可在使用者的计算机上储存的 Cookie 数量有所限制。大多数浏览器只允许每个网站储存 20 Cookie ,如果您尝试储存更多 Cookie ,则浏览器会舍弃最旧的 Cookie 。有些浏览器还会对 Cookie 数量加上绝对限制,通常可接受来自所有网站共 300 Cookie
您比较可能碰到的 Cookie 限制是使用者可设定其浏览器拒绝接受 Cookie 。您无法解决这个问题,除非完全避免使用 Cookie ,而使用不同的机制来储存使用者特定信息。储存使用者信息的常用方法是「工作阶段状态」,但工作阶段状态会依赖 Cookie ,稍后我会在 Cookie 和工作阶段状态 中说明。
注意     如需有关状态管理和在 Web 应用程序中储存信息的选项之详细信息,请参阅《 Introduction to Web Forms State Management ( 英文 ) 和《 State Management ( 英文 )
原则上,虽然 Cookie 在应用程序中非常有用,但应用程序不应该依赖储存 Cookie 的功能。将 Cookie 用于附加功能,不要用来支持关键的重要功能。如果应用程序必须依赖 Cookie ,您可以测试浏览器是否接受 Cookie 。在本文稍后的 检查浏览器是否接受 Cookie 中将描述其做法。
撰写 Cookie
使用网页的 Response 属性来撰写 Cookie ,它会公开 (Expose) 一个对象,让您在浏览器要呈现的网页中加入新信息。 Response 对象支持称为 Cookies 的集合,可以在其中新增您要写入浏览器的 Cookie
注意    Response 对象和 Request 对象 ( 我稍后会简单介绍 ) 是网页的属性,分别包含 HttpResponse HttpRequest 类别的执行个体。如需有关 Response Request 相关文件的信息,请搜寻 HttpResponse HttpRequest
在建立 Cookie 时,您要指定几个值。首先,指定 Cookie 名称和其中储存的值。您可以建立多个 Cookie ,每一个 Cookie 都必须有唯一的名称,让您稍后要读取时可加以识别 (Cookie 依名称来储存,因此如果建立具有相同名称的两个 Cookie ,就会覆写另一个 Cookie)
您可能也要指定 Cookie 的到期时间和时间。 Cookie 通常写入使用者的磁盘中,且可能会一直保存。因此您可以指定 Cookie 到期的日期和时间。当使用者再度造访网站时,浏览器会先检查网站的 Cookie 集合。如果 Cookie 已经到期,浏览器在传送网页要求给服务器时,就不会传送这个 Cookie ,而到期的 Cookie 会被删除 ( 您的网站可能写入多个 Cookie 至使用者的计算机中,每一个 Cookie 可以各自有其到期日和时间 ) 。请注意,浏览器负责管理硬盘上的 Cookie ,这会影响在应用程序中 Cookie 的用途,我稍后会说明。
Cookie 的到期期间应该多长?这要看您使用 Cookie 作何用途而定,换句话说,这要看您的应用程序认为 Cookie 值有效的时间有多长而定。如果您使用 Cookie 来计算造访网站的使用者人数,就可以依一年内都未造访网站则视为新访客的算法,将到期时间设定为现在起算一年。相对来说,如果使用 Cookie 来储存使用者偏好设定,就可以将到期时间设定为永久不会到期 ( 例如,到期时间为 50 ) ,因为使用者可能会认为定期重设偏好设定会很烦人。您可能有时候会撰写在数秒或数分钟内到期的 Cookie 。在本章稍后的 检查浏览器是否接受 Cookie 一节,我提供建立实际存留期以秒计算的 Cookie 范例。
注意     请记住使用者可以随时清除计算机中的 Cookie 。即使您储存很久才到期的 Cookie ,使用者也可以决定删除所有的 Cookie ,清掉您储存在 Cookie 中的任何设定。
如果不要设定 Cookie 的到期时间,也会建立 Cookie ,但并非储存在使用者的硬盘中。而此 Cookie 成为使用者工作阶段信息的一部份。当使用者关闭浏览器或工作阶段逾时时,就会舍弃该 Cookie 。像这种非永续性 Cookie 对于只需短暂储存的信息,或是基于安全考虑而不应写入客户端计算机磁盘时非常方便。例如,如果使用者在公用计算机上工作,此时不要将 Cookie 写入磁盘,则非永续性 Cookie 非常有用。
您可以用许多方法新增 Cookie Response Cookies 集合中。下列范例显示完成此工作的两个方法。
方法一:
Response.Cookies["userName"].Value = "mike";
Response.Cookies["userName"].Expires = DateTime.Now.AddDays(1);
 
方法二:
System.Web.HttpCookie aCookie = new HttpCookie("userName ");
aCookie.Value = DateTime.Now.ToString();
aCookie.Expires = DateTime.Now.AddDays(1);
Response.Cookies.Add(aCookie);
此范例新增两个 Cookie Cookie 集合,一个称为「 userName 」,另一个称为「 lastVisit 」。对于第一个 Cookie ,我直接设定 Response.Cookies 集合的值。您可以用这种方式新增值至集合中,因为 Response.Cookies 是从型别 NameObjectCollectionBase 的特殊集合衍生。
对于第二个 Cookie ,我建立 Cookie 对象的执行个体 ( 型别 HttpCookie) ,设定其属性,然后使用 Add 方法将它加入 Response.Cookies 集合中。在产生 HttpCookie 对象的执行个体时,您必须将 Cookie 名称当作建构函式的一部份来传递。
这两个范例都完成相同的工作,亦即将 Cookie 写入浏览器中。您使用的方法大部份视个人偏好而定。您可能发现第二种方法比较容易设定 Cookie 属性,但您也可以看出,其间的差异并不大。
在这两种方法中,到期时间的值必须为 DateTime 型别。不过,「 lastVisited 」值也是日期时间值。不过,在此状况下,我必须将日期时间值转换成字符串。您储存在 Cookie 的任何值最终都以字符串储存。
窥视您的 Cookie
您可能发现查看建立 Cookie 的效果非常有用。查看 Cookie 非常容易 毕竟它们是文字文件,只要您找得到它们就可以了。不同的浏览器以不同方式储存 Cookie 。我将说明 Internet Explore 如何储存 Cookie ,如果您使用不同的浏览器,请检查浏览器的 [ 说明 ] 以了解处理 Cookie 的方式。
检视 Cookie 的一种方便方式是让 Internet Explore 为您找出来。在 Internet Explore 中,在 [ 工具 ] 菜单选择 [Internet 选项 ] 。在 [ 一般 ] 标签中,按一下 [ 设定 ] ,再按一下 [ 检视档案 ] Internet Explore 会开启显示其所有暂存盘的窗口,包括 Cookie 。在此窗口中寻找名称以「 Cookie 」开头的档案,或寻找文字文件。连按两下 Cookie ,就会在预设的文字文件中将它开启。
或者也可以藉由寻找硬盘中的文字文件来浏览 Cookie Internet Explore 在档案中储存网站的 Cookie ,这个文件名称的格式为 <user>@<domain>.txt ,其中 <user> 就是您的账户名称。例如,如果您的名称是 mikepope ,而您造访网站 www.contoso.com ,则该网站的 Cookie 将称为 mikepope@www.contoso.txt ( 此名称可能包含序号,例如 mikepope@www.contoso[1].txt )
Cookie 文字文件是使用者特定的档案,因此可用账户来区隔。例如在 Windows XP 中,您将在如下列名称的目录中找到 Cookie
c:/Documents and Settings/<user>/Cookies
若要寻找您建立的 Cookie ,您会发现依 [ 修改日期 ] 将目录排序后再寻找最近的档案,会很有帮助。
您可以使用文字编辑器开启 Cookie 。如果档案包含多重 Cookie ,它们会以星号 (*) 隔开。每一个 Cookie 的第一行是它的名称,第二行是它的值。其余各行具有 Cookie 的管理信息,例如到期日和时间。在 Cookie 中还有一个简单的总和检查码,如果您变更 Cookie 名称或值的长度,浏览器将侦测到此一窜改而舍弃该 Cookie
多重值 Cookie ( 子机码 )
先前的范例对您要储存的每个值使用一个 Cookie ( 使用者名称、上次造访时间 ) 。您也可以在单一 Cookie 中储存多重名称 - 值对。名称 - 值对是指「机码」或「子机码」,视您所读取的对象而定 ( 子机码配置成类似 URL 中的查询字符串,您也许碰巧熟悉该结构 ) 。例如,您可以建立称为「 userInfo 」的单一 Cookie ,其中具有子机码「 userName 」和「 lastVisit 」,以取代建立称为「 userName 」和「 lastVisit 」两个个别的 Cookie
有许多原因要使用子机码来取代个别的 Cookie 。很明显地,将相关或类似的信息放入单一 Cookie 中比较有条理。此外,因为所有的信息都在单一 Cookie 中, Cookie 属性 ( 例如到期时间 ) 可套用至所有的信息中 ( 反之,如果您要指定不同的到期时间给不同类型的信息,就应该将信息分别存放在个别的 Cookie )
具有子机码的 Cookie 还能协助您维持 Cookie 的大小。如先前在 Cookie 限制 所提示的, Cookie 上限为 4096 个字节,而且每一个网站不可以储存超过 20 Cookie 。藉由使用具有子机码的单一 Cookie ,可以使用少于指派给网站的 20 Cookie 。此外,单一 Cookie 会多占用大约 50 个字符 ( 到期信息等 ) ,加上储存在其中的数值长度,总共接近 4K 上限。如果以储存五个子机码来取代五个个别的 Cookie ,可以节省个别 Cookie 多用的空间,大约可节省 200 个字节。
若要建立具有子机码的 Cookie ,可以使用许多撰写单一 Cookie 的语法。下列范例显示撰写相同 Cookie 的两种方法,各具有两个子机码:
方法一 :
Response.Cookies["userInfo"]["userName"] = "mike";
Response.Cookies["userInfo"]["lastVisit"]= DateTime.Now.ToString();
Response.Cookies["userInfo"].Expires = DateTime.Now.AddDays(1);
 
方法二 :
System.Web.HttpCookie aCookie = new HttpCookie["userInfo "];
aCookie.Values["userName"]= "mike";
aCookie.Values["lastVisit"] = DateTime.Now.ToString();
aCookie.Expires = DateTime.Now.AddDays(1);
Response.Cookies.Add(aCookie);
控制 Cookie 范围
在预设状况下,网站的所有 Cookie 都一起储存在客户端,而且会和任何网站要求一并传送至服务器 换句话说,网站中的每一个网页都可以取得该网站的所有 Cookie 。有时候您可能希望以特定方式使用 Cookie ,您可以用两种方式设定 Cookie 的范围:
·                  Cookie 的范围限制在服务器上的数据夹,实际上可让您将 Cookie 限制到网站的应用程序。
·                  将范围设定在网域,可让您指定网域中哪个子网域可以存取 Cookie
Cookie 限制在数据夹或应用程序
若要将 Cookie 限制在服务器上的数据夹,请设定 Cookie Path 属性,如下所示:
System.Web.HttpCookie appCookie = new HttpCookie("AppCookie");
 appCookie.Value = "written " + Now.ToString();
appCookie.Expires = Now.AddDays(1);
appCookie.Path = "/Application1";
Response.Cookies.Add(appCookie);
当然,您也可以直接设定 Response.Cookies 来撰写 Cookie ,如我先前所述。
路径可以为网站根目录或虚拟根目录之下的实体路径。只有在 Application1 数据夹或虚拟根目录之下的网页才可以使用 Cookie 。例如,如果网站称为 www.contoso.com ,先前范例所建立的 Cookie 就可供路径为 http://www.contoso.com/Application1/ 的网页及该数据夹之下的任何网页使用。不过,此 Cookie 不可供其它应用程序中的网页使用,例如 http://www.contoso.com/Application2/ http://www.contoso.com/
秘诀     针对 Internet Explorer Mozilla 浏览器进行的一些测试显示路径区分大小写。一般来说, Windows 服务器上的 URL 并不区分大小写,但这似乎是例外。您不能控制使用者在浏览器中如何键入 URL ,但是如果您的应用程序依赖连结特定路径的 Cookie ,请确定您建立的任何超级链接中的 URL 都符合 Path 属性值的大小写。
限制 Cookie 范围为网域
在预设状况下, Cookie 与特定网域相关联。例如,如果您的网站是 www.contoso.com ,使用者向该网站要求任何网页时,您写入的 Cookie 会传送至服务器 ( 具有特定路径值的 Cookie 除外,如我在前一节中所述 ) 。如果您的网站有子网域 例如 contoso.com sales.contoso.com support.contoso.com 则您可以关联 Cookie 与特定子网域。若要如此,请设定 Cookie Domain 属性,如下所示:
Response.Cookies["domain"].Value = DateTime.Now.ToString();
Response.Cookies["domain"].Expires = DateTime.Now.AddDays(1);
Response.Cookies("domain").Domain = "support.contoso.com"
以这种方式设定网域时, Cookie 只能供特定子网域中的网页使用。
您也可以使用 Domain 属性来建立在多重子网域之间共享的 Cookie 。例如,设定网域如下:
Response.Cookies["domain"].Value = DateTime.Now.ToString();
Response.Cookies["domain"].Expires = DateTime.Now.AddDays(1);
Response.Cookies("domain").Domain = "contoso.com";
Cookie 就可供主网域和 sales.contoso.com support.contoso.com 使用。
读取 Cookie
当浏览器对服务器提出要求时,它会随着要求来传送该服务器的 Cookie 。在您的 ASP.NET 应用程序中,可以使用 Request 对象读取 Cookie Request 对象的结构在本质上与 Response 对象的结构相同,因此从 Request 对象读取 Cookie 的方式类似于将 Cookie 写入 Response 对象的方式。下列范例显示取得称为「 username 」的 Cookie 值的两种方法,然后将其值显示在 Label 控件中:
if (Request.Cookies["userName"]!=null)
{
Label1.Text = Server.HtmlEncode(Request.Cookies["userName"].Value);
}
 
if (Request.Cookies["userName"] !=null)
{
   System.Web.HttpCookie aCookie = new HttpCookie(Request.Cookies["userName"]);
   Label1.Text = Server.HtmlEncode(aCookie.Value);
}
 
在尝试取得 Cookie 值之前,您应该确定该 Cookie 存在。否则,您将得到 System.NullReferenceException 例外状况。请注意,在将 Cookie 显示于网页之前,我呼叫 HttpServerUtility.HtmlEncode 方法将其内容编码。因为我要显示 Cookie 的内容 ( 通常并不需要如此 ) 才需要如此做,而且我要确定怀有恶意的使用者并未偷偷将可执行的指令码放入 Cookie 中。如需有关 Cookie 安全性的详细信息,请参阅 Cookie 和安全性
注意     因为不同的浏览器以不同方式储存 Cookie ,相同计算机上的不同浏览器未必可以相互读取另一个 Cookie 。例如,如果您先使用 Internet Explorer 来测试网页,稍后使用不同的浏览器再测试网页,则第二个浏览器找不到 Internet Explorer 所储存的 Cookie 。当然,多数人通常在所有的 Web 互动中使用相同的浏览器,因此在大多数状况下这并不是问题。不过,如果是测试应用程序的浏览器兼容性,就会有这个问题。
读取 Cookie 中子机码值的方式与设定其值的方式类似。下面是取得子机码值的一种方法:
if (Request.Cookies["userInfo"] !=null)
{
   Label1.Text = Server.HtmlEncode(Request.Cookies["userInfo"]["userName"]);
   Label2.text = Server.HtmlEncode(Request.Cookies["userInfo"]["lastVisit"]);
}
在先前的范例中,我取得子机码「 lastVisit 」的值,这是先前设定给 DateTime 字符串表示的值。请记住, Cookie 以字符串来储存其值,因此如果您要使用 lastVisit 值作为日期,就必须将它转换成日期。
Cookie 中的子机码是型别 NameValueCollection 。因此,取得个别子机码的另一个方法是取得子机码集合,然后依名称撷取子机码,如下所示:
if (Request.Cookies["userInfo"] !=null)
{
   System.Collections.Specialized.NameValueCollection UserInfoCookieCollection = new System.Collections.Specialized.NameValueCollection();
UserInfoCookieCollection = Request.Cookies["userInfo "].Values;
Label1.Text = Server.HtmlEncode(UserInfoCookieCollection["userName"]);
Label2.Text = Server.HtmlEncode(UserInfoCookieCollection["lastVisit "]);
}
和设定 Cookie 一样,用来读取 Cookie 的方法因人而异。
何谓到期日?
您可以读取 Cookie 的名称和值,但 Cookie 也没有多少其它值得再学习的了。您可以取得 Domain Path 属性,但那些属性没有多大用处。例如,您可以读取 Domain 属性,但是如果您的网页与 Cookie 不在相同的网域中,本来就不会收到 Cookie
您无法读取的是 Cookie 的到期日和时间。当浏览器传送 Cookie 信息至服务器时,浏览器不包含到期信息。您可以读取 Expires 属性,但它传回的日期 - 时间值总是零。
稍早在 撰写 Cookie 中,我提到浏览器负责管理 Cookie Expires 属性就是其中一个例子。 Expires 属性的主要目的是协助浏览器管理它所储存的 Cookie 。由服务器的观点来看, Cookie 可以存在或不存在,到期日在服务器端并非有用的信息。因此,浏览器在传送 Cookie 时不提供这个信息。如果您在意 Cookie 的到期日,您必须将它重设,稍后我会在 修改和删除 Cookie 中说明。
更明确来说,在传送 Cookie 至浏览器之前,您可以读取 Cookie 中您已经在 Response 对象设定的 Expires 属性。不过,您无法由 Request 对象中取回到期日。
读取 Cookie 集合
先前的范例假设您要读取已知其名称的特定 Cookie 。您偶尔可能需要读取网页可用的所有 Cookie 。若要读取网页可用的所有 Cookie 的名称和值,您可以使用如下的程序代码来依序读取 Request.Cookies 集合:
string output = "";
System.Web.HttpCookie aCookie = new HttpCookie("info");
for(int i=0;i< Request.Cookies.Count;i++)
{
    aCookie = Request.Cookies[i];
    output += "Cookie 名称 = " +Server.HtmlEncode(aCookie.Name) + "<br>";
    output += "Cookie = " + Server.HtmlEncode(aCookie.Value) + "<br><br>";
}
Label1.Text = output;
注意     在执行此程序代码时,您可能会看到称为「 ASP.NET_SessionId 」的 Cookie 。那是 ASP.NET 用来储存您的工作阶段唯一识别码的 Cookie 。此工作阶段 Cookie 并不会一直存在您的硬盘中。如需有关工作阶段 Cookie 的详细信息,请参阅本文稍后的 Cookie 和工作阶段状态
先前范例的限制在于如果 Cookie 有子机码,显示画面会将子机码显示为单一名称 / 值字符串。 Cookie 属性 HasKeys 告诉您该 Cookie 是否有子机码。如果有,您可以展开至子机码集合,以取得个别子机码的名称和值。
如我先前所提示,您可以从 Cookie 属性 Values 取得子机码的相关信息,这是型别 NameValueCollection 的集合。您可藉由索引值直接从 Values 集合读取子机码值。对应的子机码名称可在 Values 集合的 AllKeys 成员中找到,它会传回字符串集合。
下列范例显示修改过的先前范例。此范例使用 HasKeys 属性来测试子机码,如果侦测到子机码,就会从 Values 集合取得子机码:
int i ;
              int j;
              string output = "";
              System.Web.HttpCookie aCookie = new HttpCookie("info");
              string subkeyName;
              string subkeyValue;
              for( i = 0 ;i<Request.Cookies.Count;i++)
              {
                   aCookie = Request.Cookies[i];
                   output += " 名称 = " + aCookie.Name + "<br>";
                   if (aCookie.HasKeys)
            {
                for(j = 0;j<aCookie.Values.Count;j++)
                {
                   subkeyName = Server.HtmlEncode(aCookie.Values.AllKeys[j]);
                   subkeyValue = Server.HtmlEncode(aCookie.Values[j]);
                   output += " 子机码名称 = " + subkeyName + "<br>";
                   output += " 子机码值 = " + subkeyValue + "<br><br>";
                }
            }
          
            else
                   {
                       output += " 值 = " + Server.HtmlEncode(aCookie.Value) + "<br><br>";
                   }
              }
                   Label1.Text = output;
或者,您可以撷取子机码作为 NameValueCollection 对象,如下所示:
System.Web.HttpCookie aCookie = new HttpCookie("info");
              string subkeyName;
              string subkeyValue;
              string output = "";
              for(int i=0;i<Request.Cookies.Count;i++)
              {
                   aCookie=Request.Cookies[i];
                   output += " 名称 = " + aCookie.Name + "<br>";
                   if(aCookie.HasKeys)
                   {
                       System.Collections.Specialized.NameValueCollection CookieValues = new System.Collections.Specialized.NameValueCollection();
                       CookieValues = aCookie.Values;
                       string []CookieValueNames = CookieValues.AllKeys;
                       for(int j = 0;j<CookieValues.Count;j++)
                       {
                            subkeyName = Server.HtmlEncode(CookieValueNames[j]);
                            subkeyValue = Server.HtmlEncode(CookieValues[j]);
                            output += " 子机码名称 = " +subkeyName + "<br>";
                            output += " 子机码值 = " +subkeyValue + "<br><br>";
                       }
                   }
                   else
                   {
                       output += " 值 = " + aCookie.Value + "<br><br>";
                   }
              }
 
 
 
              Label1.Text = output;
注意     请记住,我只呼叫 Server.HtmlEncode 方法,因为我要在网页中显示 Cookie 的值。如果您只要测试 Cookie 的值,在使用前就不必先加以编码。
修改和删除 Cookie
有时候您可能要修改 Cookie ,或许是变更其值或延长其到期时间 ( 请记住,您无法读取到期日,因为浏览器并未传送到期日信息至服务器 )
当然,您实际上并非直接变更 Cookie 。虽然您可以从 Request.Cookies 集合取得 Cookie 并加以管理,但 Cookie 本身仍存在使用者硬盘中。因此修改 Cookie 事实上是以新的值建立新的 Cookie ,然后将此 Cookie 传送至浏览器来覆写客户端上的旧版本。
下列范例显示如何变更储存使用者造访网站次数的 Cookie 值:
int counter;
              if( Request.Cookies["counter"]==null)
              {
                   counter = 0;
              }
              else
              {
                   counter =Convert.ToInt32(Request.Cookies["counter"]);
              }
              counter += 1;
              Response.Cookies["counter"] = counter.ToString();
              Response.Cookies["counter"].Expires = DateTime.Now.AddDays(1);
              Label1.Text = counter.ToString();
或者:
System.Web.HttpCookie ctrCookie=null;
              int counter;
              if(Request.Cookies["counter"] == null)
                   ctrCookie = new System.Web.HttpCookie("counter");
              else
                   ctrCookie = Request.Cookies["counter"];
              counter = Convert.ToInt32(ctrCookie.Value) + 1;
              ctrCookie.Value = counter.ToString();
              ctrCookie.Expires = DateTime.Now.AddDays(1);
              Response.Cookies.Add(ctrCookie);
          Label1.Text = Request.Cookies["counter"].Value.ToString();
删除 Cookie
删除 Cookie 实际将它从使用者的硬盘中移除 也是修改的一种。您不可以直接移除 Cookie ,因为此 Cookie 在使用者的计算机中。不过,您可以让浏览器为您删除 Cookie 。技巧在于以上述方式修改 Cookie ( 也就是使用相同名称建立新的 Cookie) ,但是将 Cookie 的到期日设定为比今天还早。当浏览器检查 Cookie 到期日时,浏览器就会舍弃已经过时的 Cookie
因此,,删除任何一个 Cookie 与建立 Cookie 的方法相同,只是使用比今天还早的日期。下列范例比删除单一 Cookie 还有趣 其中显示删除目前网域中所有 Cookie 的一种方法:
System.Web.HttpCookie aCookie = new HttpCookie("DEL");
             int limit = Request.Cookies.Count;
                               for(int i = 0;i<limit;i++)
                               {
                               aCookie = Request.Cookies[i];
                               aCookie.Expires = DateTime.Now.AddDays(-1);
                               Response.Cookies.Add(aCookie);
                               }
修改或删除子机码
修改个别子机码与建立子机码的方法相同:
Response.Cookies["userInfo"]["lastVisit"] = DateTime.Now.ToString();
Response.Cookies["userInfo"].Expires = DateTime.Now.AddDays(1);
更复杂的问题是如何个别删除子机码。您不仅是重设 Cookie 的到期时间,因为那会移除整个 Cookie 而不是单一子机码。解决方法是管理保存子机码的 Cookie Values 集合。首先从 Request.Cookies 对象中取得 Cookie 以重新建立 Cookie 。然后呼叫 Values 集合的 Remove 方法,将要删除的子机码名称传送给 Remove 方法。然后和平常一样,您可以将修改过的 Cookie 加入 Response.Cookies 集合中,将修改完成的 Cookie 传回给浏览器。
下列程序代码显示如何删除子机码。在此范例中,以变量来指定要移除的子机码名称。
string subkeyName = " userName ";
                                              System.Web.HttpCookie aCookie = Request.Cookies["userInfo "];
                                              aCookie.Values.Remove(subkeyName);
                                              aCookie.Expires = DateTime.Now.AddDays(1);
                                              Response.Cookies.Add(aCookie);
Cookie 和安全性
在使用 Cookie 时,必须了解到它们所衍生的安全性漏洞。说到安全性,我指的不是稍早在 何谓 Cookie? 中说明的隐私权问题,隐私权比较像是关心 Cookie 信息使用方式的使用者问题。 Cookie 的安全性问题类似于从客户端取得数据的问题。首先,就应用程序来说, Cookie 是另一种形式的使用者输入,因此可能会受到窥视和诈骗。使用者至少可看到储存在 Cookie 中的数据,因为 Cookie 就在使用者自己的计算机中。如果使用者需要,也可以在浏览器将 Cookie 传送给您之前加以变更。
结论是您绝不可在 Cookie 中储存机密—不可储存使用者名称、密码、信用卡号码等。请勿将不可让使用者或窃取 Cookie 的人得手的任何信息储存在 Cookie 中。
同理,对从 Cookie 取得的信息采保留态度。请勿认定数据与您写入时相同,使用 Cookie 值时,采取和处理使用者在网页中键入的数据相同的安全防护。例如,在网页显示数值之前,我在 Cookie 的内容上套用 HTML 编码。这是从使用者取得任何信息之后加以清理的标准方法,而处理 Cookie 也一样。
另一个问题是 Cookie 在浏览器和服务器之间以纯文字传送,可以拦截 Web 数据流量的任何人都可以读取 Cookie 。您可以设定 Cookie 属性,使其只在使用 Secure Sockets Layer (SSL ,又称为 https://) 联机时才传送 Cookie SSL 并不能保护 Cookie 在使用者的计算机上免于遭到读取或处理,但是它可以防止 Cookie 在传输中遭到拦截。在本文中并不讨论 SSL ,但是要了解到您可以新增传输防护至 Cookie 中。如需有关 SSL 的详细信息,请参阅《 Secure Sockets Layer: Protect Your E-Commerce Web Site with SSL and Digital Certificates ( 英文 )
既然有这些安全性问题,您要如何安全地使用 Cookie 呢?您可以在 Cookie 中储存非关键性数据,例如使用者偏好设定或一些其它假使遭到破坏,对应用程序不会有重大影响的信息。如果您一定要在 Cookie 中储存机密信息,例如使用者 ID ,您可以将 Cookie 加密。一个可能是使用 [ASP.NET 窗体验证 ] 公用程序来建立存成 Cookie 的验证票证。在本文中并不讨论加密,但如果您要在 Cookie 中储存机密数据,就应该深入了解如何隐藏信息,以免遭到窥视和诈骗。
您可以在《 Mitigating Cross-site Scripting With HTTP-only Cookies ( 英文 ) 一文中找到有关 Cookie 和安全性漏洞的详细信息。
检查浏览器是否接受 Cookie
稍早在 Cookie 限制 一节中曾提到使用者可能将其浏览器设定为拒绝接受 Cookie 的潜在问题。您如何知道是否可以写入和读取 Cookie ?如果无法写入 Cookie ,并不会产生错误 ( 例如 Response.Cookies 不会掷出例外状况 ) ,因为服务器不会追踪网页呈现之后所发生的事。浏览器同样也不会传送有关目前的 Cookie 设定的任何信息至服务器 ( 更明白来说, HttpBrowserCapabilities.Cookies Property 属性不会告诉您是否启用 Cookie ,它只会告诉您目前的浏览器是否原本就支持 Cookie)
决定是否接受 Cookie 的一种方法是尝试写入 Cookie ,然后再尝试读取。如果无法读取您写入的 Cookie ,就表示浏览器关闭 Cookie 功能。
我举出一个简单的范例来说明如何测试是否接受 Cookie 。此范例含有两个网页。在第一个网页中,我写入 Cookie ,然后将浏览器重新导向至第二个网页。第二个网页尝试读取 Cookie 。然后再将浏览器重新导向回到第一个网页,在 URL 中加入包含测试结果的查询字符串变量。
第一个网页的程序代码如下:
private void Page_Load(object sender, System.EventArgs e)
if (!Page.IsPostBack )
{
     if (Request.QueryString["AcceptsCookies"]!=null)
{
           Response.Cookies["TestCookie"].Value = "ok";
           Response.Cookies["TestCookie"].Expires = DateTime.Now.AddMinutes(1);
           Response.Redirect("TestForCookies.aspx?redirect="+ Server.UrlEncode(Request.Url.ToString()));
}
      else
{
           labelAcceptsCookies.Text = " 接受 cookies = " +Request.QueryString["AcceptsCookies"];
          }
}
 }
此网页先测试这是否为自动回传,如果不是,此网页会搜寻包含测试结果的查询字符串变量 ( AcceptsCookies ) 。如果没有查询字符串变量,表示测试尚未完成,因此程序代码会写出称为「 TestCookie 」的 Cookie 。在写出 Cookie 之后,此范例呼叫 Response.Redirect 传送至测试网页 (TestForCookies.aspx) 。附加至测试网页 URL 之后的是称为 redirect 的查询字符串变量,其中包含目前网页的 URL ,如此可让您在执行测试之后重新导向回到此网页。
此测试网页可包含整个程序代码,它不需要包含控件。下面是我使用的程序代码:
private void Page_Load(object sender, System.EventArgs e)
{
               string redirect = Request.QueryString["redirect"];
               int acceptsCookies;
                               //Cookie 是否被接受?
               if(Request.Cookies["TestCookie"]==null)
               {
               acceptsCookies = 0; // 没有 cookie ,不能被接受 ;
               }
               else
               {
               acceptsCookies = 1;
               Response.Cookies["TestCookie"].Expires = DateTime.Now.AddDays(-1); // 删除测试用 cookie
               }
               Response.Redirect(redirect+"?AcceptsCookies=" + acceptsCookies,true);
}
在读取 redirect 查询字符串变量之后,此程序代码会尝试读取 Cookie 。基于管理目的,如果此 Cookie 确实存在,就会立即将它删除。完成测试时,此程序代码会使用 redirect 查询字符串变量中传回的 URL 来建构新的 URL 。新的 URL 还包含含有测试结果的查询字符串变量。最后一个步骤是使用新的 URL 将浏览器重新导向至原始网页。
此范例非常简单,但藉由尝试此程序并查看其发生的状况,可说明测试的基本原则。最大好处是将 Cookie 测试结果保存在永久存留的储存区,让使用者不用在每次检视原始网页时重复执行测试。不过,这比表面上看起来还难以处理。很明显地, Cookie 无法使用。另一个可能是将测试结果储存在工作阶段状态中,但是在预设状况下,工作阶段状态也依赖 Cookie ,如果浏览器不接受 Cookie ,工作阶段状态也就无法运作。最后一个问题的解决方法是使用「无 Cookie 」工作阶段状态。在下一节中,将提供工作阶段状态如何处理 Cookie 的简介。
Cookie 和工作阶段状态
当使用者浏览网站时,服务器会为该使用者建立唯一的工作阶段,在使用者造访期间会持续存在。对于每一个工作阶段, ASP.NET 都维持服务器式的结构 ( 「工作阶段状态」 ) ,应用程序可在此储存使用者特定信息。如需详细信息,请参阅《 Session State ( 英文 )
ASP.NET 需要可以追踪每一个使用者的工作阶段 ID ,因此可以将使用者对应至服务器上的工作阶段状态信息。在预设状况下, ASP.NET 使用非永续性 Cookie 来储存工作阶段状态。如果使用 读取 Cookie 一节中的「读取 Cookie 集合」范例程序代码,您可能有看到工作阶段状态 Cookie
不过,如果使用者的浏览器停用 Cookie ,工作阶段状态就无法使用 Cookie 来储存工作阶段 ID ,且工作阶段状态无法使用。这就是我稍早在 检查浏览器是否接受 Cookie 一节中为何说测试 Cookie 之后,可能无法实际将测试结果存入工作阶段状态中的原因 没有 Cookie 就没有工作阶段状态。
ASP.NET 提供「无 Cookie 」工作阶段形式的暂时解决方法。您可以设定应用程序不在 Cookie 储存工作阶段 ID ,而是储存在网站网页的 URL 中。藉由将工作阶段 ID 保存在 URL 中, ASP.NET ID 储存在浏览器中,也就是说,可以在使用者要求另一个网页时将它取回。
Cookie 工作阶段可以避开浏览器拒绝 Cookie 的问题,让您使用工作阶段状态。如果您的应用程序依赖工作阶段状态,您可能要将它设定成使用无 Cookie 工作阶段。不过,在一些状况下,如果使用者与他人共享 URL 或许在使用者工作阶段使用中将 URL 以电子邮件传送给同事,则两个使用者可能会结束共享的相同工作阶段,而产生无法预期的结果。
如需设定应用程序使用无 Cookie 工作阶段的详细信息,请参阅 Knowledge Base 文章《 INFO: ASP.NET State Management Overview ( 英文 )
 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值