|
Cookie 提供了一種在 Web 應(yīng)用程序中存儲用戶特定信息的方法。例如,當用戶訪問您的站點時,您可以使用 Cookie 存儲用戶首選項或其他信息。當該用戶再次訪問您的網(wǎng)站時,應(yīng)用程序便可以檢索以前存儲的信息。
什么是 Cookie?
Cookie 是一小段文本信息,伴隨著用戶請求和頁面在 Web 服務(wù)器和瀏覽器之間傳遞。Cookie 包含每次用戶訪問站點時 Web 應(yīng)用程序都可以讀取的信息。
例如,如果在用戶請求站點中的頁面時應(yīng)用程序發(fā)送給該用戶的不僅僅是一個頁面,還有一個包含日期和時間的 Cookie,用戶的瀏覽器在獲得頁面的同時還獲得了該 Cookie,并將它存儲在用戶硬盤上的某個文件夾中。
以后,如果該用戶再次請求您站點中的頁面,當該用戶輸入 URL 時,瀏覽器便會在本地硬盤上查找與該 URL 關(guān)聯(lián)的 Cookie。如果該 Cookie 存在,瀏覽器便將該 Cookie 與頁請求一起發(fā)送到您的站點。然后,應(yīng)用程序便可以確定該用戶上次訪問站點的日期和時間。您可以使用這些信息向用戶顯示一條消息,也可以檢查到期日期。
Cookie 與網(wǎng)站關(guān)聯(lián),而不是與特定的頁面關(guān)聯(lián)。因此,無論用戶請求站點中的哪一個頁面,瀏覽器和服務(wù)器都將交換 Cookie 信息。用戶訪問不同站點時,各個站點都可能會向用戶的瀏覽器發(fā)送一個 Cookie;瀏覽器會分別存儲所有 Cookie。
Cookie 幫助網(wǎng)站存儲有關(guān)訪問者的信息。一般來說,Cookie 是一種保持 Web 應(yīng)用程序連續(xù)性(即執(zhí)行狀態(tài)管理)的方法。除短暫的實際交換信息的時間外,瀏覽器和 Web 服務(wù)器間都是斷開連接的。對于用戶向 Web 服務(wù)器發(fā)出的每個請求,Web 服務(wù)器都會單獨處理。但是在很多情況下,Web 服務(wù)器在用戶請求頁時識別出用戶會十分有用。例如,購物站點上的 Web 服務(wù)器跟蹤每位購物者,這樣站點就可以管理購物車和其他的用戶特定信息。因此,Cookie 可以作為一種名片,提供相關(guān)的標識信息幫助應(yīng)用程序確定如何繼續(xù)執(zhí)行。
使用 Cookie 能夠達到多種目的,所有這些目的都是為了幫助網(wǎng)站記住用戶。例如,一個實施民意測驗的站點可以簡單地將 Cookie 作為一個 Boolean 值,用它來指示用戶的瀏覽器是否已參與了投票,這樣用戶便無法進行第二次投票。要求用戶登錄的站點則可以通過 Cookie 來記錄用戶已經(jīng)登錄,這樣用戶就不必每次都輸入憑據(jù)。
Cookie 的限制
大多數(shù)瀏覽器支持最大為 4096 字節(jié)的 Cookie。由于這限制了 Cookie 的大小,最好用 Cookie 來存儲少量數(shù)據(jù),或者存儲用戶 ID 之類的標識符。用戶 ID 隨后便可用于標識用戶,以及從數(shù)據(jù)庫或其他數(shù)據(jù)源中讀取用戶信息。(有關(guān)存儲用戶信息安全建議的信息,請參見下面的“Cookie 和安全性”一節(jié)。)
瀏覽器還限制站點可以在用戶計算機上存儲的 Cookie 的數(shù)量。大多數(shù)瀏覽器只允許每個站點存儲 20 個 Cookie;如果試圖存儲更多 Cookie,則最舊的 Cookie 便會被丟棄。有些瀏覽器還會對它們將接受的來自所有站點的 Cookie 總數(shù)作出絕對限制,通常為 300 個。
您可能遇到的 Cookie 限制是用戶可以將其瀏覽器設(shè)置為拒絕接受 Cookie。如果定義一個 P3P 隱私策略,并將其放置在網(wǎng)站的根目錄中,則更多的瀏覽器將接受您站點的 Cookie。但是,您可能會不得不完全放棄 Cookie,而通過其他機制來存儲用戶特定的信息。存儲用戶信息的常用方法是會話狀態(tài),但會話狀態(tài)依賴于 Cookie,這一點在后面的“Cookie 和會話狀態(tài)”一節(jié)中說明。
注意
有關(guān) Web 應(yīng)用程序中的狀態(tài)管理和用于保存信息的選項的更多信息,請參見 ASP.NET 狀態(tài)管理概述 和 ASP.NET 狀態(tài)管理建議。
雖然 Cookie 在應(yīng)用程序中非常有用,但應(yīng)用程序不應(yīng)依賴于能夠存儲 Cookie。不要使用 Cookie 支持關(guān)鍵功能。如果應(yīng)用程序必須依賴于 Cookie,則可以通過測試確定瀏覽器是否將接受 Cookie。請參見本主題后面的“檢查瀏覽器是否接受 Cookie”一節(jié)。
編寫 Cookie
瀏覽器負責管理用戶系統(tǒng)上的 Cookie。Cookie 通過 HttpResponse 對象發(fā)送到瀏覽器,該對象公開稱為 Cookies 的集合。可以將 HttpResponse 對象作為 Page 類的 Response 屬性來訪問。要發(fā)送給瀏覽器的所有 Cookie 都必須添加到此集合中。創(chuàng)建 Cookie 時,需要指定 Name 和 Value。每個 Cookie 必須有一個唯一的名稱,以便以后從瀏覽器讀取 Cookie 時可以識別它。由于 Cookie 按名稱存儲,因此用相同的名稱命名兩個 Cookie 會導(dǎo)致其中一個 Cookie 被覆蓋。
還可以設(shè)置 Cookie 的到期日期和時間。用戶訪問編寫 Cookie 的站點時,瀏覽器將刪除過期的 Cookie。只要應(yīng)用程序認為 Cookie 值有效,就應(yīng)將 Cookie 的有效期設(shè)置為這一段時間。對于永不過期的 Cookie,可將到期日期設(shè)置為從現(xiàn)在起 50 年。
注意
用戶可隨時清除其計算機上的 Cookie。即便存儲的 Cookie 距到期日期還有很長時間,但用戶還是可以決定刪除所有 Cookie,清除 Cookie 中存儲的所有設(shè)置。
如果沒有設(shè)置 Cookie 的有效期,仍會創(chuàng)建 Cookie,但不會將其存儲在用戶的硬盤上。而會將 Cookie 作為用戶會話信息的一部分進行維護。當用戶關(guān)閉瀏覽器時,Cookie 便會被丟棄。這種非永久性 Cookie 很適合用來保存只需短時間存儲的信息,或者保存由于安全原因不應(yīng)該寫入客戶端計算機上的磁盤的信息。例如,如果用戶在使用一臺公用計算機,而您不希望將 Cookie 寫入該計算機的磁盤中,這時就可以使用非永久性 Cookie。
可以通過多種方法將 Cookie 添加到 Cookies 集合中。下面的示例演示兩種編寫 Cookie 的方法:
復(fù)制代碼 代碼如下:
Response.Cookies["userName"].Value = "patrick";
Response.Cookies["userName"].Expires = DateTime.Now.AddDays(1);
HttpCookie aCookie = new HttpCookie("lastVisit");
aCookie.Value = DateTime.Now.ToString();
aCookie.Expires = DateTime.Now.AddDays(1);
Response.Cookies.Add(aCookie);
此示例向 Cookies 集合添加兩個 Cookie,一個名為 userName,另一個名為 lastVisit。對于第一個 Cookie,Cookies 集合的值是直接設(shè)置的。可以通過這種方式向集合添加值,因為 Cookies 是從 NameObjectCollectionBase 類型的專用集合派生的。
對于第二個 Cookie,代碼創(chuàng)建了一個 HttpCookie 類型的對象實例,設(shè)置其屬性,然后通過 Add 方法將其添加到 Cookies 集合。在實例化 HttpCookie 對象時,必須將該 Cookie 的名稱作為構(gòu)造函數(shù)的一部分進行傳遞。
這兩個示例都完成了同一任務(wù),即向瀏覽器寫入一個 Cookie。在這兩種方法中,有效期值必須為 DateTime 類型。但是,lastVisited 值也是日期時間值。因為所有 Cookie 值都存儲為字符串,因此,必須將日期時間值轉(zhuǎn)換為 String。
多值 Cookie
可以在 Cookie 中存儲一個值,如用戶名和上次訪問時間。也可以在一個 Cookie 中存儲多個名稱/值對。名稱/值對稱為子鍵。(子鍵布局類似于 URL 中的查詢字符串。)例如,不要創(chuàng)建兩個名為 userName 和 lastVisit 的單獨 Cookie,而可以創(chuàng)建一個名為 userInfo 的 Cookie,其中包含兩個子鍵 userName 和 lastVisit。
您可能會出于多種原因來使用子鍵。首先,將相關(guān)或類似的信息放在一個 Cookie 中很方便。此外,由于所有信息都在一個 Cookie 中,所以諸如有效期之類的 Cookie 屬性就適用于所有信息。(反之,如果要為不同類型的信息指定不同的到期日期,就應(yīng)該把信息存儲在單獨的 Cookie 中。)
帶有子鍵的 Cookie 還可幫助您限制 Cookie 文件的大小。正如前面“Cookie 的限制”一節(jié)中所提到的,Cookie 通常限制為 4096 字節(jié),并且每個站點最多可存儲 20 個 Cookie。使用帶子鍵的單個 Cookie,使用的 Cookie 數(shù)就不會超過分配給站點的 20 個的限制。此外,一個 Cookie 會占用大約 50 個字符的系統(tǒng)開銷(用于保存有效期信息等),再加上其中存儲的值的長度,其總和接近 4096 字節(jié)的限制。如果存儲五個子鍵而不是五個單獨的 Cookie,便可節(jié)省單獨 Cookie 的系統(tǒng)開銷,節(jié)省大約 200 字節(jié)。
若要創(chuàng)建帶子鍵的 Cookie,您可以使用編寫單個 Cookie 的各種語法。下面的示例演示用于編寫同一 Cookie 的兩種方法,其中的每個 Cookie 都帶有兩個子鍵:
復(fù)制代碼 代碼如下:
Response.Cookies["userInfo"]["userName"] = "patrick";
Response.Cookies["userInfo"]["lastVisit"] = DateTime.Now.ToString();
Response.Cookies["userInfo"].Expires = DateTime.Now.AddDays(1);
HttpCookie aCookie = new HttpCookie("userInfo");
aCookie.Values["userName"] = "patrick";
aCookie.Values["lastVisit"] = DateTime.Now.ToString();
aCookie.Expires = DateTime.Now.AddDays(1);
Response.Cookies.Add(aCookie);
控制 Cookie 的范圍
默認情況下,一個站點的全部 Cookie 都一起存儲在客戶端上,而且所有 Cookie 都會隨著對該站點發(fā)送的任何請求一起發(fā)送到服務(wù)器。也就是說,一個站點中的每個頁面都能獲得該站點的所有 Cookie。但是,可以通過兩種方式設(shè)置 Cookie 的范圍:
將 Cookie 的范圍限制到服務(wù)器上的某個文件夾,這允許您將 Cookie 限制到站點上的某個應(yīng)用程序。
將范圍設(shè)置為某個域,這允許您指定域中的哪些子域可以訪問 Cookie。
將 Cookie 限制到某個文件夾或應(yīng)用程序
若要將 Cookie 限制到服務(wù)器上的某個文件夾,請按下面的示例設(shè)置 Cookie 的 Path 屬性:
復(fù)制代碼 代碼如下:
HttpCookie appCookie = new HttpCookie("AppCookie");
appCookie.Value = "written " + DateTime.Now.ToString();
appCookie.Expires = DateTime.Now.AddDays(1);
appCookie.Path = "/Application1";
Response.Cookies.Add(appCookie);
注意
還可以通過將 Cookie 直接添加到 Cookies 集合的方式來編寫 Cookie,如先前的示例所示。
路徑可以是站點根目錄下的物理路徑,也可以是虛擬根目錄。所產(chǎn)生的效果是 Cookie 只能用于 Application1 文件夾或虛擬根目錄中的頁面。例如,如果您的站點名稱為 http://www.contoso.com/,則在前面示例中創(chuàng)建的 Cookie 將只能用于路徑為 http://www.contoso.com/Application1/ 的頁面以及該文件夾下的所有頁面。但是,Cookie 將不能用于其他應(yīng)用程序中的頁面,如 http://www.contoso.com/Application2/ 或 http://www.contoso.com/ 中的頁面。
注意
在某些瀏覽器中,路徑區(qū)分大小寫。您無法控制用戶如何在其瀏覽器中鍵入 URL,但如果應(yīng)用程序依賴于與特定路徑相關(guān)的 Cookie,請確保您創(chuàng)建的所有超鏈接中的 URL 與 Path 屬性值的大小寫相匹配。
限制 Cookie 的域范圍
默認情況下,Cookie 與特定域關(guān)聯(lián)。例如,如果您的站點是 http://www.contoso.com/,那么當用戶向該站點請求任何頁時,您編寫的 Cookie 就會被發(fā)送到服務(wù)器。(這可能不包括帶有特定路徑值的 Cookie。)如果站點具有子域(例如,contoso.com、sales.contoso.com 和 support.contoso.com),則可以將 Cookie 與特定的子域關(guān)聯(lián)。若要執(zhí)行此操作,請設(shè)置 Cookie 的 Domain 屬性,如此示例所示:
Response.Cookies["domain"].Value = DateTime.Now.ToString();
Response.Cookies["domain"].Expires = DateTime.Now.AddDays(1);
Response.Cookies["domain"].Domain = "support.contoso.com";
當以此方式設(shè)置域時,Cookie 將僅可用于指定的子域中的頁面。還可以使用 Domain 屬性創(chuàng)建可在多個子域間共享的 Cookie,如下面的示例所示:
復(fù)制代碼 代碼如下:
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
瀏覽器向服務(wù)器發(fā)出請求時,會隨請求一起發(fā)送該服務(wù)器的 Cookie。在 ASP.NET 應(yīng)用程序中,可以使用 HttpRequest 對象讀取 Cookie,該對象可用作 Page 類的 Request 屬性使用。HttpRequest 對象的結(jié)構(gòu)與 HttpResponse 對象的結(jié)構(gòu)基本相同,因此,可以從 HttpRequest 對象中讀取 Cookie,并且讀取方式與將 Cookie 寫入 HttpResponse 對象的方式基本相同。下面的代碼示例演示兩種方法,通過這兩種方法可獲取名為 username 的 Cookie 的值,并將其值顯示在 Label 控件中:
復(fù)制代碼 代碼如下:
if(Request.Cookies["userName"] != null)
Label1.Text = Server.HtmlEncode(Request.Cookies["userName"].Value);
if(Request.Cookies["userName"] != null)
{
HttpCookie aCookie = Request.Cookies["userName"];
Label1.Text = Server.HtmlEncode(aCookie.Value);
}
在嘗試獲取 Cookie 的值之前,應(yīng)確保該 Cookie 存在;如果該 Cookie 不存在,將會收到 NullReferenceException 異常。還請注意在頁面中顯示 Cookie 的內(nèi)容前,先調(diào)用 HtmlEncode 方法對 Cookie 的內(nèi)容進行編碼。這樣可以確保惡意用戶沒有向 Cookie 中添加可執(zhí)行腳本。有關(guān) Cookie 安全性的更多信息,請參見“Cookie 和安全性”一節(jié)。
注意
由于不同的瀏覽器存儲 Cookie 的方式不同,因此,同一計算機上的不同瀏覽器沒有必要能夠讀取彼此的 Cookie。例如,如果使用 InterNET Explorer 測試一個頁面,然后再使用其他瀏覽器進行測試,那么后者將不會找到 InterNET Explorer 保存的 Cookie。
讀取 Cookie 中子鍵值的方法與設(shè)置該值的方法類似。下面的代碼示例演示獲取子鍵值的一種方法:
復(fù)制代碼 代碼如下:
if(Request.Cookies["userInfo"] != null)
{
Label1.Text =
Server.HtmlEncode(Request.Cookies["userInfo"]["userName"]);
Label2.Text =
Server.HtmlEncode(Request.Cookies["userInfo"]["lastVisit"]);
}
在上面的示例中,代碼讀取子鍵 lastVisit 的值,該值先前被設(shè)置為字符串表示形式的 DateTime 值。Cookie 將值存儲為字符串,因此,如果要將 lastVisit 值作為日期使用,必須將其轉(zhuǎn)換為適當?shù)念愋停绱耸纠荆?
DateTime dt;
dt = DateTime.Parse(Request.Cookies["userInfo"]["lastVisit"]);
Cookie 中的子鍵被類型化為 NameValueCollection 類型的集合。因此,獲取單個子鍵的另一種方法是獲取子鍵集合,然后再按名稱提取子鍵值,如下面的示例所示:
復(fù)制代碼 代碼如下:
if(Request.Cookies["userInfo"] != null)
{
System.Collections.Specialized.NameValueCollection
UserInfoCookieCollection;
UserInfoCookieCollection = Request.Cookies["userInfo"].Values;
Label1.Text =
Server.HtmlEncode(UserInfoCookieCollection["userName"]);
Label2.Text =
Server.HtmlEncode(UserInfoCookieCollection["lastVisit"]);
}
更改 Cookie 的到期日期
瀏覽器負責管理 Cookie,而 Cookie 的到期時間和日期可幫助瀏覽器管理 Cookie 的存儲。因此,雖然可以讀取 Cookie 的名稱和值,但無法讀取 Cookie 的到期日期和時間。當瀏覽器向服務(wù)器發(fā)送 Cookie 信息時,并不包括有效期信息。(Cookie 的 Expires 屬性始終返回值為 0 的日期時間值。)如果您擔心 Cookie 的到期日期,必須重新設(shè)置該 Cookie,該過程在“修改和刪除 Cookie”一節(jié)中介紹。
注意
可以在向瀏覽器發(fā)送 Cookie 之前讀取已在 HttpResponse 對象中設(shè)置的 Cookie 的 Expires 屬性。但是,您無法從返回的 HttpRequest 對象中獲取有效期。
讀取 Cookie 集合
有時,您可能需要讀取可供頁面使用的所有 Cookie。若要讀取可供頁面使用的所有 Cookie 的名稱和值,可以使用如下代碼依次通過 Cookies 集合。
復(fù)制代碼 代碼如下:
System.Text.StringBuilder output = new System.Text.StringBuilder();
HttpCookie aCookie;
for(int i=0; i<Request.Cookies.Count; i++)
{
aCookie = Request.Cookies[i];
output.Append("Cookie name = " + Server.HtmlEncode(aCookie.Name)
+ "<br />");
output.Append("Cookie value = " + Server.HtmlEncode(aCookie.Value)
+ "<br /><br />");
}
Label1.Text = output.ToString();
注意
在運行此代碼時,可能會看到一個名為 ASP.NET_SessionId 的 Cookie。ASP.NET 使用該 Cookie 來存儲您的會話的唯一標識符。會話 Cookie 不會保存在您的硬盤上。有關(guān)會話 Cookie 的更多信息,請參見本主題后面的“Cookie 和會話狀態(tài)”一節(jié)。
上面的示例有一個限制:如果 Cookie 有子鍵,則會以一個名稱/值字符串來顯示子鍵。可以讀取 Cookie 的 HasKeys 屬性,以確定 Cookie 是否有子鍵。如果有,則可以讀取子鍵集合以獲取各個子鍵名稱和值。可以通過索引值直接從 Values 集合中讀取子鍵值。相應(yīng)的子鍵名稱可在 Values 集合的 AllKeys 成員中獲得,該成員將返回一個字符串數(shù)組。還可以使用 Values 集合的 Keys 成員。但是,首次訪問 AllKeys 屬性時,該屬性會被緩存。相比之下,每次訪問 Keys 屬性時,該屬性都生成一個數(shù)組。因此在同一頁請求的上下文內(nèi),在隨后訪問時,AllKeys 屬性要快得多。
下面的示例演示對前一示例的修改。該示例使用 HasKeys 屬性來測試是否存在子鍵,如果檢測到子鍵,便從 Values 集合獲取子鍵:
復(fù)制代碼 代碼如下:
for(int i=0; i<Request.Cookies.Count; i++)
{
aCookie = Request.Cookies[i];
output.Append("Name = " + aCookie.Name + "<br />");
if(aCookie.HasKeys)
{
for(int j=0; j<aCookie.Values.Count; j++)
{
subkeyName = Server.HtmlEncode(aCookie.Values.AllKeys[j]);
subkeyValue = Server.HtmlEncode(aCookie.Values[j]);
output.Append("Subkey name = " + subkeyName + "<br />");
output.Append("Subkey value = " + subkeyValue +
"<br /><br />");
}
}
else
{
output.Append("Value = " + Server.HtmlEncode(aCookie.Value) +
"<br /><br />");
}
}
Label1.Text = output.ToString();
或者,可將子鍵作為 NameValueCollection 對象提取,如下面的示例所示:
復(fù)制代碼 代碼如下:
System.Text.StringBuilder output = new System.Text.StringBuilder();
HttpCookie aCookie;
string subkeyName;
string subkeyValue;
for (int i = 0; i < Request.Cookies.Count; i++)
{
aCookie = Request.Cookies[i];
output.Append("Name = " + aCookie.Name + "<br />");
if (aCookie.HasKeys)
{
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.Append("Subkey name = " + subkeyName + "<br />");
output.Append("Subkey value = " + subkeyValue +
"<br /><br />");
}
}
else
{
output.Append("Value = " + Server.HtmlEncode(aCookie.Value) +
"<br /><br />");
}
}
Label1.Text = output.ToString();
修改和刪除 Cookie
不能直接修改 Cookie。更改 Cookie 的過程涉及創(chuàng)建一個具有新值的新 Cookie,然后將其發(fā)送到瀏覽器來覆蓋客戶端上的舊版本 Cookie。下面的代碼示例演示如何更改存儲用戶對站點的訪問次數(shù)的 Cookie 的值:
復(fù)制代碼 代碼如下:
int counter;
if (Request.Cookies["counter"] == null)
counter = 0;
else
{
counter = int.Parse(Request.Cookies["counter"].Value);
}
counter++;
Response.Cookies["counter"].Value = counter.ToString();
Response.Cookies["counter"].Expires = DateTime.Now.AddDays(1);
刪除 Cookie刪除 Cookie(即從用戶的硬盤中物理移除 Cookie)是修改 Cookie 的一種形式。由于 Cookie 在用戶的計算機中,因此無法將其直接移除。但是,可以讓瀏覽器來為您刪除 Cookie。該技術(shù)是創(chuàng)建一個與要刪除的 Cookie 同名的新 Cookie,并將該 Cookie 的到期日期設(shè)置為早于當前日期的某個日期。當瀏覽器檢查 Cookie 的到期日期時,瀏覽器便會丟棄這個現(xiàn)已過期的 Cookie。下面的代碼示例演示刪除應(yīng)用程序中所有可用 Cookie 的一種方法:
復(fù)制代碼 代碼如下:
HttpCookie aCookie;
string cookieName;
int limit = Request.Cookies.Count;
for (int i=0; i<limit; i++)
{
cookieName = Request.Cookies[i].Name;
aCookie = new HttpCookie(cookieName);
aCookie.Expires = DateTime.Now.AddDays(-1);
Response.Cookies.Add(aCookie);
}
修改或刪除子鍵修改單個子鍵的方法與創(chuàng)建它的方法相同,如下面的示例所示:
Response.Cookies["userInfo"]["lastVisit"] = DateTime.Now.ToString();
Response.Cookies["userInfo"].Expires = DateTime.Now.AddDays(1);
若要刪除單個子鍵,可以操作 Cookie 的 Values 集合,該集合用于保存子鍵。首先通過從 Cookies 對象中獲取 Cookie 來重新創(chuàng)建 Cookie。然后您就可以調(diào)用 Values 集合的 Remove 方法,將要刪除的子鍵的名稱傳遞給 Remove 方法。接著,將 Cookie 添加到 Cookies 集合,這樣 Cookie 便會以修改后的格式發(fā)送回瀏覽器。下面的代碼示例演示如何刪除子鍵。在此示例中,要移除的子鍵的名稱在變量中指定。
復(fù)制代碼 代碼如下:
string subkeyName;
subkeyName = "userName";
HttpCookie aCookie = Request.Cookies["userInfo"];
aCookie.Values.Remove(subkeyName);
aCookie.Expires = DateTime.Now.AddDays(1);
Response.Cookies.Add(aCookie);
Cookie 和安全性
Cookie 的安全性問題與從客戶端獲取數(shù)據(jù)的安全性問題類似。在應(yīng)用程序中,Cookie 是另一種形式的用戶輸入,因此很容易被他們非法獲取和利用。由于 Cookie 保存在用戶自己的計算機上,因此,用戶至少能看到您存儲在 Cookie 中的數(shù)據(jù)。用戶還可以在瀏覽器向您發(fā)送 Cookie 之前更改該 Cookie。
千萬不要在 Cookie 中存儲敏感信息,如用戶名、密碼、信用卡號等等。不要在 Cookie 中放置任何不應(yīng)由用戶掌握的內(nèi)容,也不要放可能被其他竊取 Cookie 的人控制的內(nèi)容。
同樣,不要輕信從 Cookie 中得到的信息。不要假定數(shù)據(jù)與您寫出時相同;處理 Cookie 值時采用的安全措施應(yīng)該與處理網(wǎng)頁中用戶鍵入的數(shù)據(jù)時采用的安全措施相同。本主題前面的示例演示在頁面中顯示值前,先對 Cookie 內(nèi)容進行 HTML 編碼的方法,這與在顯示從用戶處得到的任何信息之前的做法相同。
Cookie 以明文形式在瀏覽器和服務(wù)器間發(fā)送,任何可以截獲 Web 通信的人都可以讀取 Cookie。可以設(shè)置 Cookie 屬性,使 Cookie 只能在使用安全套接字層 (SSL) 的連接上傳輸。SSL 并不能防止保存在用戶計算機上的 Cookie 被讀取或操作,但可防止 Cookie 在傳輸過程中被讀取,因為 Cookie 已被加密。有關(guān)更多信息,請參見 Web 應(yīng)用程序的基本安全實施策略。
確定瀏覽器是否接受 Cookie
用戶可將其瀏覽器設(shè)置為拒絕接受 Cookie。在不能寫入 Cookie 時不會引發(fā)任何錯誤。同樣,瀏覽器也不向服務(wù)器發(fā)送有關(guān)其當前 Cookie 設(shè)置的任何信息。
注意
Cookies 屬性不指示 Cookie 是否啟用。它僅指示當前瀏覽器是否原本支持 Cookie。
確定 Cookie 是否被接受的一種方法是嘗試編寫一個 Cookie,然后再嘗試讀取該 Cookie。如果無法讀取您編寫的 Cookie,則可以假定瀏覽器不接受 Cookie。
下面的代碼示例演示如何測試瀏覽器是否接受 Cookie。此示例由兩個頁面組成。第一個頁面寫出 Cookie,然后將瀏覽器重定向到第二個頁面。第二個頁面嘗試讀取該 Cookie。然后再將瀏覽器重定向回第一個頁面,并將帶有測試結(jié)果的查詢字符串變量添加到 URL。
第一個頁面的代碼如下所示:
復(fù)制代碼 代碼如下:
protected void Page_Load(object sender, 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
{
Label1.Text = "Accept cookies = " +
Server.UrlEncode(
Request.QueryString["AcceptsCookies"]);
}
}
}
該頁面首先測試以確定是不是回發(fā),如果不是,則查找包含測試結(jié)果的查詢字符串變量名 AcceptsCookies。如果不存在查詢字符串變量,表示測試還未完成,因此代碼會寫出一個名為 TestCookie 的 Cookie。寫出 Cookie 后,該示例調(diào)用 Redirect 來切換到 TestForCookies.ASPx 測試頁。附加到測試頁 URL 的信息是一個名為 redirect 的查詢字符串變量,該變量包含當前頁的 URL;這樣就能在執(zhí)行測試后重定向回此頁面。
測試頁可完全由代碼組成;不需要包含控件。下面的代碼示例闡釋了該測試頁。
復(fù)制代碼 代碼如下:
protected void Page_Load(object sender, EventArgs e)
{
string redirect = Request.QueryString["redirect"];
string acceptsCookies;
if(Request.Cookies["TestCookie"] ==null)
acceptsCookies = "no";
else
{
acceptsCookies = "yes";
// Delete test cookie.
Response.Cookies["TestCookie"].Expires =
DateTime.Now.AddDays(-1);
}
Response.Redirect(redirect + "?AcceptsCookies=" + acceptsCookies,
true);
}
讀取重定向查詢字符串變量后,代碼嘗試讀取 Cookie。出于管理目的,如果該 Cookie 存在,則立即刪除。測試完成后,代碼通過 redirect 查詢字符串變量傳遞給它的 URL 構(gòu)造一個新的 URL。新 URL 也包括一個包含測試結(jié)果的查詢字符串變量。最后一步是使用新 URL 將瀏覽器重定向到最初頁面。
該示例的一個改進是可將 Cookie 測試結(jié)果保存到永久存儲區(qū)(如數(shù)據(jù)庫)中,這樣就不必在用戶每次查看最初頁面時都重復(fù)進行測試。(默認情況下,在會話狀態(tài)中存儲測試結(jié)果需要 Cookie。)
Cookie 和會話狀態(tài)
當用戶導(dǎo)航到您的站點時,服務(wù)器為該用戶建立唯一的會話,會話將一直延續(xù)到用戶訪問結(jié)束。ASP.NET 會為每個會話維護會話狀態(tài)信息,應(yīng)用程序可在會話狀態(tài)信息中存儲用戶特定信息。有關(guān)更多信息,請參見會話狀態(tài)概述主題。
ASP.NET 必須跟蹤每個用戶的會話 ID,以便可以將用戶映射到服務(wù)器上的會話狀態(tài)信息。默認情況下,ASP.NET 使用非永久性 Cookie 來存儲會話狀態(tài)。但是,如果用戶已在瀏覽器上禁用 Cookie,會話狀態(tài)信息便無法存儲在 Cookie 中。
ASP.NET 提供了無 Cookie 會話作為替代。可以將應(yīng)用程序配置為不將會話 ID 存儲在 Cookie 中,而存儲在站點中頁面的 URL 中。如果應(yīng)用程序依賴于會話狀態(tài),可以考慮將其配置為使用無 Cookie 會話。但是在較少的情況下,如果用戶與他人共享 URL(可能是用戶將 URL 發(fā)送給同事,而該用戶的會話仍然處于活動狀態(tài)),則最終這兩個用戶可能共享同一個會話,結(jié)果將難以預(yù)料。有關(guān)將應(yīng)用程序配置為使用無 Cookie 會話的更多信息,請參見 ASP.NET 狀態(tài)管理概述主題。
AspNet技術(shù):ASP.NET Cookie 操作實現(xiàn),轉(zhuǎn)載需保留來源!
鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯(lián)系我們修改或刪除,多謝。