天天看點

ASP.NET Cookie 概述(msdn)

Cookie 是一小段文本資訊,伴随着使用者請求和頁面在 Web 伺服器和浏覽器之間傳遞。Cookie 包含每次使用者通路站點時 Web 應用程式都可以讀取的資訊。

方案

Cookie 提供了一種在 Web 應用程式中存儲使用者特定資訊的方法。例如,當使用者通路您的站點時,您可以使用 Cookie 存儲使用者首選項或其他資訊。當該使用者再次通路您的網站時,應用程式便可以檢索以前存儲的資訊。

背景

Cookie 是一小段文本資訊,伴随着使用者請求和頁面在 Web 伺服器和浏覽器之間傳遞。Cookie 包含每次使用者通路站點時 Web 應用程式都可以讀取的資訊。

例如,如果在使用者請求站點中的頁面時應用程式發送給該使用者的不僅僅是一個頁面,還有一個包含日期和時間的 Cookie,使用者的浏覽器在獲得頁面的同時還獲得了該 Cookie,并将它存儲在使用者硬碟上的某個檔案夾中。

以後,如果該使用者再次請求您站點中的頁面,當該使用者輸入 URL 時,浏覽器便會在本地硬碟上查找與該 URL 關聯的 Cookie。如果該 Cookie 存在,浏覽器便将該 Cookie 與頁請求一起發送到您的站點。然後,應用程式便可以确定該使用者上次通路站點的日期和時間。您可以使用這些資訊向使用者顯示一條消息,也可以檢查到期日期。

Cookie 與網站關聯,而不是與特定的頁面關聯。是以,無論使用者請求站點中的哪一個頁面,浏覽器和伺服器都将交換 Cookie 資訊。使用者通路不同站點時,各個站點都可能會向使用者的浏覽器發送一個 Cookie;浏覽器會分别存儲所有 Cookie。

Cookie 幫助網站存儲有關通路者的資訊。一般來說,Cookie 是一種保持 Web 應用程式連續性(即執行狀态管理)的方法。除短暫的實際交換資訊的時間外,浏覽器和 Web 伺服器間都是斷開連接配接的。對于使用者向 Web 伺服器發出的每個請求,Web 伺服器都會單獨處理。但是在很多情況下,Web 伺服器在使用者請求頁時識别出使用者會十分有用。例如,購物站點上的 Web 伺服器跟蹤每位購物者,這樣站點就可以管理購物車和其他的使用者特定資訊。是以,Cookie 可以作為一種名片,提供相關的辨別資訊幫助應用程式确定如何繼續執行。

使用 Cookie 能夠達到多種目的,所有這些目的都是為了幫助網站記住使用者。例如,一個實施民意測驗的站點可以簡單地将 Cookie 作為一個 Boolean 值,用它來訓示使用者的浏覽器是否已參與了投票,這樣使用者便無法進行第二次投票。要求使用者登入的站點則可以通過 Cookie 來記錄使用者已經登入,這樣使用者就不必每次都輸入憑據。

Cookie 的限制

大多數浏覽器支援最大為 4096 位元組的 Cookie。由于這限制了 Cookie 的大小,最好用 Cookie 來存儲少量資料,或者存儲使用者 ID 之類的辨別符。使用者 ID 随後便可用于辨別使用者,以及從資料庫或其他資料源中讀取使用者資訊。(有關存儲使用者資訊安全建議的資訊,請參見下面的“Cookie 和安全性”一節。)

浏覽器還限制站點可以在使用者計算機上存儲的 Cookie 的數量。大多數浏覽器隻允許每個站點存儲 20 個 Cookie;如果試圖存儲更多 Cookie,則最舊的 Cookie 便會被丢棄。有些浏覽器還會對它們将接受的來自所有站點的 Cookie 總數作出絕對限制,通常為 300 個。

您可能遇到的 Cookie 限制是使用者可以将其浏覽器設定為拒絕接受 Cookie。如果定義一個 P3P 隐私政策,并将其放置在網站的根目錄中,則更多的浏覽器将接受您站點的 Cookie。但是,您可能會不得不完全放棄 Cookie,而通過其他機制來存儲使用者特定的資訊。存儲使用者資訊的常用方法是會話狀态,但會話狀态依賴于 Cookie,這一點在後面的“Cookie 和會話狀态”一節中說明。

PS:有關 Web 應用程式中的狀态管理和用于儲存資訊的選項的更多資訊,請參見 ASP.NET 狀态管理概述 和 ASP.NET 狀态管理建議。

雖然 Cookie 在應用程式中非常有用,但應用程式不應依賴于能夠存儲 Cookie。不要使用 Cookie 支援關鍵功能。如果應用程式必須依賴于 Cookie,則可以通過測試确定浏覽器是否将接受 Cookie。請參見本主題後面的“檢查浏覽器是否接受 Cookie”一節。

編寫 Cookie

浏覽器負責管理使用者系統上的 Cookie。Cookie 通過 HttpResponse 對象發送到浏覽器,該對象公開稱為 Cookies 的集合。可以将 HttpResponse 對象作為 Page 類的 Response 屬性來通路。要發送給浏覽器的所有 Cookie 都必須添加到此集合中。建立 Cookie 時,需要指定 Name 和 Value。每個 Cookie 必須有一個唯一的名稱,以便以後從浏覽器讀取 Cookie 時可以識别它。由于 Cookie 按名稱存儲,是以用相同的名稱命名兩個 Cookie 會導緻其中一個 Cookie 被覆寫。

還可以設定 Cookie 的到期日期和時間。使用者通路編寫 Cookie 的站點時,浏覽器将删除過期的 Cookie。隻要應用程式認為 Cookie 值有效,就應将 Cookie 的有效期設定為這一段時間。對于永不過期的 Cookie,可将到期日期設定為從現在起 50 年。

PS:使用者可随時清除其計算機上的 Cookie。即便存儲的 Cookie 距到期日期還有很長時間,但使用者還是可以決定删除所有 Cookie,清除 Cookie 中存儲的所有設定

如果沒有設定 Cookie 的有效期,仍會建立 Cookie,但不會将其存儲在使用者的硬碟上。而會将 Cookie 作為使用者會話資訊的一部分進行維護。當使用者關閉浏覽器時,Cookie 便會被丢棄。這種非永久性 Cookie 很适合用來儲存隻需短時間存儲的資訊,或者儲存由于安全原因不應該寫入用戶端計算機上的磁盤的資訊。例如,如果使用者在使用一台公用計算機,而您不希望将 Cookie 寫入該計算機的磁盤中,這時就可以使用非永久性 Cookie。

可以通過多種方法将 Cookie 添加到 Cookies 集合中。下面的示例示範兩種編寫 Cookie 的方法:

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 集合的值是直接設定的。可以通過這種方式向集合添加值,因為 Cookies 是從 NameObjectCollectionBase 類型的專用集合派生的。

對于第二個 Cookie,代碼建立了一個 HttpCookie 類型的對象執行個體,設定其屬性,然後通過 Add 方法将其添加到 Cookies 集合。在執行個體化 HttpCookie 對象時,必須将該 Cookie 的名稱作為構造函數的一部分進行傳遞。

這兩個示例都完成了同一任務,即向浏覽器寫入一個 Cookie。在這兩種方法中,有效期值必須為 DateTime 類型。但是,lastVisited 值也是日期時間值。因為所有 Cookie 值都存儲為字元串,是以,必須将日期時間值轉換為 String。

多值 Cookie

可以在 Cookie 中存儲一個值,如使用者名和上次通路時間。也可以在一個 Cookie 中存儲多個名稱/值對。名稱/值對稱為子鍵。(子鍵布局類似于 URL 中的查詢字元串。)例如,不要建立兩個名為 userName 和 lastVisit 的單獨 Cookie,而可以建立一個名為 userInfo 的 Cookie,其中包含兩個子鍵 userName 和 lastVisit。

您可能會出于多種原因來使用子鍵。首先,将相關或類似的資訊放在一個 Cookie 中很友善。此外,由于所有資訊都在一個 Cookie 中,是以諸如有效期之類的 Cookie 屬性就适用于所有資訊。(反之,如果要為不同類型的資訊指定不同的到期日期,就應該把資訊存儲在單獨的 Cookie 中。)

帶有子鍵的 Cookie 還可幫助您限制 Cookie 檔案的大小。正如前面“Cookie 的限制”一節中所提到的,Cookie 通常限制為 4096 位元組,并且每個站點最多可存儲 20 個 Cookie。使用帶子鍵的單個 Cookie,使用的 Cookie 數就不會超過配置設定給站點的 20 個的限制。此外,一個 Cookie 會占用大約 50 個字元的系統開銷(用于儲存有效期資訊等),再加上其中存儲的值的長度,其總和接近 4096 位元組的限制。如果存儲五個子鍵而不是五個單獨的 Cookie,便可節省單獨 Cookie 的系統開銷,節省大約 200 位元組。

若要建立帶子鍵的 Cookie,您可以使用編寫單個 Cookie 的各種文法。下面的示例示範用于編寫同一 Cookie 的兩種方法,其中的每個 Cookie 都帶有兩個子鍵:

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);

      

控制 Cookie 的範圍

預設情況下,一個站點的全部 Cookie 都一起存儲在用戶端上,而且所有 Cookie 都會随着對該站點發送的任何請求一起發送到伺服器。也就是說,一個站點中的每個頁面都能獲得該站點的所有 Cookie。但是,可以通過兩種方式設定 Cookie 的範圍:

  • 将 Cookie 的範圍限制到伺服器上的某個檔案夾,這允許您将 Cookie 限制到站點上的某個應用程式。
  • 将範圍設定為某個域,這允許您指定域中的哪些子域可以通路 Cookie。

将 Cookie 限制到某個檔案夾或應用程式

若要将 Cookie 限制到伺服器上的某個檔案夾,請按下面的示例設定 Cookie 的 Path 屬性: 

HttpCookie appCookie = new HttpCookie("AppCookie");
appCookie.Value = "written " + DateTime.Now.ToString();
appCookie.Expires = DateTime.Now.AddDays(1);
appCookie.Path = "/Application1";
Response.Cookies.Add(appCookie);
      

PS:還可以通過将 Cookie 直接添加到 Cookies 集合的方式來編寫 Cookie,如先前的示例所示。

路徑可以是站點根目錄下的實體路徑,也可以是虛拟根目錄。所産生的效果是 Cookie 隻能用于 Application1 檔案夾或虛拟根目錄中的頁面。例如,如果您的站點名稱為 www.contoso.com,則在前面示例中建立的 Cookie 将隻能用于路徑為 http://www.contoso.com/Application1/ 的頁面以及該檔案夾下的所有頁面。但是,Cookie 将不能用于其他應用程式中的頁面,如 http://www.contoso.com/Application2/ 或 http://www.contoso.com/ 中的頁面。

PS:在某些浏覽器中,路徑區分大小寫。您無法控制使用者如何在其浏覽器中鍵入 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 應用程式中,可以使用 HttpRequest 對象讀取 Cookie,該對象可用作 Page 類的 Request 屬性使用。HttpRequest 對象的結構與 HttpResponse 對象的結構基本相同,是以,可以從 HttpRequest 對象中讀取 Cookie,并且讀取方式與将 Cookie 寫入 HttpResponse 對象的方式基本相同。下面的代碼示例示範兩種方法,通過這兩種方法可擷取名為 username 的 Cookie 的值,并将其值顯示在 Label 控件中:

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 的值之前,應確定該 Cookie 存在;如果該 Cookie 不存在,将會收到 NullReferenceException 異常。還請注意在頁面中顯示 Cookie 的内容前,先調用 HtmlEncode 方法對 Cookie 的内容進行編碼。這樣可以確定惡意使用者沒有向 Cookie 中添加可執行腳本。有關 Cookie 安全性的更多資訊,請參見“Cookie 和安全性”一節。

PS:由于不同的浏覽器存儲 Cookie 的方式不同,是以,同一計算機上的不同浏覽器沒有必要能夠讀取彼此的 Cookie。例如,如果使用
Internet Explorer 測試一個頁面,然後再使用其他浏覽器進行測試,那麼後者将不會找到 Internet Explorer 儲存的
Cookie。

讀取 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 值作為日期使用,必須将其轉換為适當的類型,如此示例所示:

DateTime dt;
dt = DateTime.Parse(Request.Cookies["userInfo"]["lastVisit"]);

Cookie 中的子鍵被類型化為 NameValueCollection 類型的集合。是以,擷取單個子鍵的另一種方法是擷取子鍵集合,然後再按名稱提取子鍵值,如下面的示例所示:

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 的到期日期和時間。當浏覽器向伺服器發送 Cookie 資訊時,并不包括有效期資訊。(Cookie 的 Expires 屬性始終傳回值為 0 的日期時間值。)如果您擔心 Cookie 的到期日期,必須重新設定該 Cookie,該過程在“修改和删除 Cookie”一節中介紹。

PS:可以在向浏覽器發送 Cookie 之前讀取已在 HttpResponse 對象中設定的 Cookie 的 Expires 屬性。但是,您無法從傳回的 HttpRequest 對象中擷取有效期。

讀取 Cookie 集合

有時,您可能需要讀取可供頁面使用的所有 Cookie。若要讀取可供頁面使用的所有 Cookie 的名稱和值,可以使用如下代碼依次通過 Cookies 集合。

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();

PS:在運作此代碼時,可能會看到一個名為 ASP.NET_SessionId 的 Cookie。ASP.NET 使用該 Cookie 來存儲您的會話的唯一辨別符。會話 Cookie 不會儲存在您的硬碟上。有關會話 Cookie 的更多資訊,請參見本主題後面的“Cookie 和會話狀态”一節。

      

上面的示例有一個限制:如果 Cookie 有子鍵,則會以一個名稱/值字元串來顯示子鍵。可以讀取 Cookie 的 HasKeys 屬性,以确定 Cookie 是否有子鍵。如果有,則可以讀取子鍵集合以擷取各個子鍵名稱和值。可以通過索引值直接從 Values 集合中讀取子鍵值。相應的子鍵名稱可在 Values 集合的 AllKeys 成員中獲得,該成員将傳回一個字元串數組。還可以使用 Values 集合的 Keys 成員。但是,首次通路 AllKeys 屬性時,該屬性會被緩存。相比之下,每次通路 Keys 屬性時,該屬性都生成一個數組。是以在同一頁請求的上下文内,在随後通路時,AllKeys 屬性要快得多。

下面的示例示範對前一示例的修改。該示例使用 HasKeys 屬性來測試是否存在子鍵,如果檢測到子鍵,便從 Values 集合擷取子鍵:

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 對象提取,如下面的示例所示:
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 的過程涉及建立一個具有新值的新 Cookie,然後将其發送到浏覽器來覆寫用戶端上的舊版本 Cookie。下面的代碼示例示範如何更改存儲使用者對站點的通路次數的 Cookie 的值:

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。該技術是建立一個與要删除的 Cookie 同名的新 Cookie,并将該 Cookie 的到期日期設定為早于目前日期的某個日期。當浏覽器檢查 Cookie 的到期日期時,浏覽器便會丢棄這個現已過期的 Cookie。下面的代碼示例示範删除應用程式中所有可用 Cookie 的一種方法:

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);
}
      

修改或删除子鍵

修改單個子鍵的方法與建立它的方法相同,如下面的示例所示:

Response.Cookies["userInfo"]["lastVisit"] = DateTime.Now.ToString();
Response.Cookies["userInfo"].Expires = DateTime.Now.AddDays(1);

若要删除單個子鍵,可以操作 Cookie 的 Values 集合,該集合用于儲存子鍵。首先通過從 Cookies 對象中擷取 Cookie 來重新建立 Cookie。然後您就可以調用 Values 集合的 Remove 方法,将要删除的子鍵的名稱傳遞給 Remove 方法。接着,将 Cookie 添加到 Cookies 集合,這樣 Cookie 便會以修改後的格式發送回浏覽器。下面的代碼示例示範如何删除子鍵。在此示例中,要移除的子鍵的名稱在變量中指定。

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 的安全性問題與從用戶端擷取資料的安全性問題類似。在應用程式中,Cookie 是另一種形式的使用者輸入,是以很容易被他們非法擷取和利用。由于 Cookie 儲存在使用者自己的計算機上,是以,使用者至少能看到您存儲在 Cookie 中的資料。使用者還可以在浏覽器向您發送 Cookie 之前更改該 Cookie。

千萬不要在 Cookie 中存儲敏感資訊,如使用者名、密碼、信用卡号等等。不要在 Cookie 中放置任何不應由使用者掌握的内容,也不要放可能被其他竊取 Cookie 的人控制的内容。

同樣,不要輕信從 Cookie 中得到的資訊。不要假定資料與您寫出時相同;處理 Cookie 值時采用的安全措施應該與處理網頁中使用者鍵入的資料時采用的安全措施相同。本主題前面的示例示範在頁面中顯示值前,先對 Cookie 内容進行 HTML 編碼的方法,這與在顯示從使用者處得到的任何資訊之前的做法相同。

Cookie 以明文形式在浏覽器和伺服器間發送,任何可以截獲 Web 通信的人都可以讀取 Cookie。可以設定 Cookie 屬性,使 Cookie 隻能在使用安全套接字層 (SSL) 的連接配接上傳輸。SSL 并不能防止儲存在使用者計算機上的 Cookie 被讀取或操作,但可防止 Cookie 在傳輸過程中被讀取,因為 Cookie 已被加密。有關更多資訊,請參見 Web 應用程式的基本安全實施政策。

确定浏覽器是否接受 Cookie

使用者可将其浏覽器設定為拒絕接受 Cookie。在不能寫入 Cookie 時不會引發任何錯誤。同樣,浏覽器也不向伺服器發送有關其目前 Cookie 設定的任何資訊。

PS:Cookies 屬性不訓示 Cookie 是否啟用。它僅訓示目前浏覽器是否原本支援 Cookie。

确定 Cookie 是否被接受的一種方法是嘗試編寫一個 Cookie,然後再嘗試讀取該 Cookie。如果無法讀取您編寫的 Cookie,則可以假定浏覽器不接受 Cookie。

下面的代碼示例示範如何測試浏覽器是否接受 Cookie。此示例由兩個頁面組成。第一個頁面寫出 Cookie,然後将浏覽器重定向到第二個頁面。第二個頁面嘗試讀取該 Cookie。然後再将浏覽器重定向回第一個頁面,并将帶有測試結果的查詢字元串變量添加到 URL。

第一個頁面的代碼如下所示:

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"]);
        }
    }
}
      

該頁面首先測試以确定是不是回發,如果不是,則查找包含測試結果的查詢字元串變量名 AcceptsCookies。如果不存在查詢字元串變量,表示測試還未完成,是以代碼會寫出一個名為 TestCookie 的 Cookie。寫出 Cookie 後,該示例調用 Redirect 來切換到 TestForCookies.aspx 測試頁。附加到測試頁 URL 的資訊是一個名為 redirect 的查詢字元串變量,該變量包含目前頁的 URL;這樣就能在執行測試後重定向回此頁面。

測試頁可完全由代碼組成;不需要包含控件。下面的代碼示例闡釋了該測試頁。

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 構造一個新的 URL。新 URL 也包括一個包含測試結果的查詢字元串變量。最後一步是使用新 URL 将浏覽器重定向到最初頁面。

該示例的一個改進是可将 Cookie 測試結果儲存到永久存儲區(如資料庫)中,這樣就不必在使用者每次檢視最初頁面時都重複進行測試。(預設情況下,在會話狀态中存儲測試結果需要 Cookie。)

Cookie 和會話狀态

當使用者導航到您的站點時,伺服器為該使用者建立唯一的會話,會話将一直延續到使用者通路結束。ASP.NET 會為每個會話維護會話狀态資訊,應用程式可在會話狀态資訊中存儲使用者特定資訊。有關更多資訊,請參見 ASP.NET 會話狀态概述主題。

ASP.NET 必須跟蹤每個使用者的會話 ID,以便可以将使用者映射到伺服器上的會話狀态資訊。預設情況下,ASP.NET 使用非永久性 Cookie 來存儲會話狀态。但是,如果使用者已在浏覽器上禁用 Cookie,會話狀态資訊便無法存儲在 Cookie 中。

ASP.NET 提供了無 Cookie 會話作為替代。可以将應用程式配置為不将會話 ID 存儲在 Cookie 中,而存儲在站點中頁面的 URL 中。如果應用程式依賴于會話狀态,可以考慮将其配置為使用無 Cookie 會話。但是在較少的情況下,如果使用者與他人共享 URL(可能是使用者将 URL 發送給同僚,而該使用者的會話仍然處于活動狀态),則最終這兩個使用者可能共享同一個會話,結果将難以預料。有關将應用程式配置為使用無 Cookie 會話的更多資訊,請參見 ASP.NET 狀态管理概述主題。

繼續閱讀