天天看點

細說Cookie

Cookie雖然是個很簡單的東西,但它又是WEB開發中一個很重要的用戶端資料來源,而且它可以實作擴充性很好的會話狀态, 是以我認為每個WEB開發人員都有必要對它有個清晰的認識。本文将對Cookie這個話題做一個全面的描述, 也算是我對Cookie的認識總結。

回到頂部

Cookie 概述

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

為什麼需要Cookie? 因為HTTP協定是無狀态的,對于一個浏覽器發出的多次請求,WEB伺服器無法區分 是不是來源于同一個浏覽器。是以,需要額外的資料用于維護會話。 Cookie 正是這樣的一段随HTTP請求一起被傳遞的額外資料。

Cookie能做什麼? Cookie隻是一段文本,是以它隻能儲存字元串。而且浏覽器對它有大小限制以及 它會随着每次請求被發送到伺服器,是以應該保證它不要太大。 Cookie的内容也是明文儲存的,有些浏覽器提供界面修改,是以, 不适合儲存重要的或者涉及隐私的内容。

Cookie 的限制。 大多數浏覽器支援最大為 4096 位元組的 Cookie。由于這限制了 Cookie 的大小,最好用 Cookie 來存儲少量資料,或者存儲使用者 ID 之類的辨別符。使用者 ID 随後便可用于辨別使用者,以及從資料庫或其他資料源中讀取使用者資訊。 浏覽器還限制站點可以在使用者計算機上存儲的 Cookie 的數量。大多數浏覽器隻允許每個站點存儲 20 個 Cookie;如果試圖存儲更多 Cookie,則最舊的 Cookie 便會被丢棄。有些浏覽器還會對它們将接受的來自所有站點的 Cookie 總數作出絕對限制,通常為 300 個。

通過前面的内容,我們了解到Cookie是用于維持服務端會話狀态的,通常由服務端寫入,在後續請求中,供服務端讀取。 下面本文将按這個過程看看Cookie是如何從服務端寫入,最後如何傳到服務端以及如何讀取的。

Cookie的寫、讀過程

在Asp.net中,讀寫Cookie是通過使用HttpCookie類來完成的,它的定義如下:

public sealed class HttpCookie
{
    // 擷取或設定将此 Cookie 與其關聯的域。預設值為目前域。
    public string Domain { get; set; }
    // 擷取或設定此 Cookie 的過期日期和時間(在用戶端)。
    public DateTime Expires { get; set; }
    // 擷取一個值,通過該值訓示 Cookie 是否具有子鍵。
    public bool HasKeys { get; }
    // 擷取或設定一個值,該值指定 Cookie 是否可通過用戶端腳本通路。
    // 如果 Cookie 具有 HttpOnly 屬性且不能通過用戶端腳本通路,則為 true;否則為 false。預設為 false。
    public bool HttpOnly { get; set; }
    // 擷取或設定 Cookie 的名稱。
    public string Name { get; set; }
    // 擷取或設定要與目前 Cookie 一起傳輸的虛拟路徑。預設值為目前請求的路徑。
    public string Path { get; set; }
    // 擷取或設定一個值,該值訓示是否使用安全套接字層 (SSL)(即僅通過 HTTPS)傳輸 Cookie。
    public bool Secure { get; set; }
    // 擷取或設定單個 Cookie 值。預設值為空引用。
    public string Value { get; set; }
    // 擷取單個 Cookie 對象所包含的鍵值對的集合。
    public NameValueCollection Values { get; }
    // 擷取 System.Web.HttpCookie.Values 屬性的快捷方式。
    public string this[string key] { get; set; }
}
      

Cookie寫入浏覽器的過程:我們可以使用如下代碼在Asp.net項目中寫一個Cookie 并發送到用戶端的浏覽器(為了簡單我沒有設定其它屬性)。

HttpCookie cookie = new HttpCookie("MyCookieName", "string value");
Response.Cookies.Add(cookie);
      

我想很多人都寫過類似的代碼,但是,大家有沒有想過:Cookie最後是如何發送到用戶端的呢?我們打開Fiddler來看一下吧。

細說Cookie

從上圖,您應該能發現,我們在服務端寫的Cookie,最後其實是通過HTTP的響應頭這種途徑發送到用戶端的。每一個寫入動作, 都會産生一個【Set-Cookie】的響應頭。

浏覽器正是在每次擷取請求的響應後,檢查這些頭來接收Cookie的。

Asp.net擷取Cookie的過程:我們可以使用如下代碼在Asp.net項目中讀取一個Cookie

HttpCookie cookie = Request.Cookies["MyCookieName"];
if( cookie != null )
    labCookie1.Text = cookie.Value;
else
    labCookie1.Text = "未定義";
      

代碼同樣也很簡單,還是類似的問題:大家有沒有想過,Cookie是如何傳到服務端的呢?我們還是繼續使用Fiddler來尋找答案吧。

細說Cookie

從圖檔中,我們可以發現,Cookie是放在請求頭中,發送到服務端的。如果你一直重新整理頁面,就能發現, 每次HTTP請求,Cookie都會被發送。當然了,浏覽器也不是發送它所接收到的所有Cookie,它會檢查目前要請求的域名以及目錄, 隻要這二項目與Cookie對應的Domain和Path比對,才會發送。對于Domain則是按照尾部比對的原則進行的。

是以,我在通路 www.cnblogs.com 時,浏覽器并不會将我在浏覽 www.163.com 所接收到的 Cookie 發出去。

删除Cookie:其實就是在寫Cookie時,設定Expires為一個【早于現在時間的時間】。也就是:設定此Cookie已經過期, 浏覽器接收到這個Cookie時,便會删除它們。

HttpCookie cookie = new HttpCookie("MyCookieName", null);
cookie.Expires = new DateTime(1900, 1, 1);
Response.Cookies.Add(cookie);
      

使用Cookie儲存複雜對象

前面的示例代碼大緻示範了Cookie的讀寫操作。不過,我們平時可能希望将更複雜的【自定義類型】通過Cookie來儲存, 那麼又該如何操作呢?對于這個問題,我們定義一個類型來看看如何處理。

public class DisplaySettings 
{
    public int Style;

    public int Size;
    
    public override string ToString()
    {
        return string.Format("Style = {0}, Size = {1}", this.Style, this.Size);
    }    
}
      

上面的代碼,我定義一個類型,用于儲存使用者在浏覽頁面時的顯示設定。接下來,我将介紹二種方法在Cookie中儲存并讀取它們。

方法-1,經典做法。(注意前面給出的HttpCookie定義代碼中的最後二個成員)

private void WriteCookie_2a()
{
    DisplaySettings setting = new DisplaySettings { Style = 1, Size = 24 };

    HttpCookie cookie = new HttpCookie("DisplaySettings1");
    cookie["Style"] = setting.Style.ToString();
    cookie["Size"] = setting.Size.ToString();

    Response.Cookies.Add(cookie);
}

private void ReadCookie_2a()
{
    HttpCookie cookie = Request.Cookies["DisplaySettings1"];
    if( cookie == null )
        labDisplaySettings1.Text = "未定義";
    else {
        DisplaySettings setting = new DisplaySettings();
        setting.Style = cookie["Style"].TryToInt();
        setting.Size = cookie["Size"].TryToInt();
        labDisplaySettings1.Text = setting.ToString();
    }
}
      

方法-2,将對象JSON序列化為字元串。

private void WriteCookie_2b()
{
    DisplaySettings setting = new DisplaySettings { Style = 2, Size = 48 };

    HttpCookie cookie = new HttpCookie("DisplaySettings2", setting.ToJson());
    Response.Cookies.Add(cookie);
}

private void ReadCookie_2b()
{
    HttpCookie cookie = Request.Cookies["DisplaySettings2"];
    if( cookie == null )
        labDisplaySettings2.Text = "未定義";
    else {
        DisplaySettings setting = cookie.Value.FromJson<DisplaySettings>();
        labDisplaySettings2.Text = setting.ToString();
    }
}
      

這段代碼使用了我定義的二個擴充方法。

細說Cookie

對于這二種方法,我個人更喜歡後者,因為它具有更好擴充性:如果類型增加了成員,不需要修改讀寫Cookie的代碼。

不過,這種方式産生的有些字元,比如【雙引号】,極少數浏覽器(Opera)不支援,是以需要做UrlEncode或者Base64編碼處理。

同理,對于第一種方法,遇到Value有【雙引号】時,我們同樣需要做UrlEncode或者Base64編碼處理。

Js中讀寫Cookie

Cookie并非隻能在服務端讀寫,在用戶端的浏覽器中也可以實作對它的讀寫通路。而且在JS中建立的Cookie對于服務端仍然有效(可見), 接下來我們來看看在JS中如何寫入Cookie,示範代碼将建立一個按鈕,并在點選按鈕後寫入Cookie

<input type="button" onclick="WriteCookie();" value="WriteCookie" />

<script type="text/javascript">
    function WriteCookie() {
        var cookie = "cookie_js=22222222; path=/";
        document.cookie = cookie;
    }    
</script>
      

在JS中寫Cookie很簡單,隻要給document.cookie指派一個Cookie字元串即可,至于格式,可以參考前面用Fiddle看到的結果。

再來看一下如何使用JS讀取Cookie吧。請參考如下代碼:

<input type="button" onclick="ReadCookie();" value="ReadCookie" />

<script type="text/javascript">
    function ReadCookie() {
        alert(document.cookie);
    }    
</script>
      
細說Cookie

仍然是通路document.cookie,不過,這次我們得到卻是全部的Cookie值,每個Key/Value項用分号分開,中間則用等号分開。 是以, 如果您想在JS中讀取Cookie,一定要按照這個規則來拆分并解析您要讀取的Cookie項。鑒于這樣的操作有些繁瑣, 我們可以jquery.cookie.js插件來輕松完成這個功能,有興趣的朋友也可以看一下它是如何處理的。 這個插件的代碼比較少,這裡就直接貼出, 

細說Cookie

注意哦:前面我們看到了HttpCookie有個HttpOnly屬性,如果它為true,那麼JS是讀不到那個Cookie的,也就是說: 我們如果在服務端生成的Cookie不希望在JS中能被通路,可以在寫Cookie時,設定這個屬性。不過,通過一些工具,還是可以看到它們。

接下來,我們再來看看Asp.net中Cookie有哪些應用。

Cookie在Session中的應用

在Asp.net中,HttpContext, Page對象都有個Session的對象,我們可以使用它來友善地在服務端儲存一些與會話相關的資訊。

前面我們也提到過,HTTP協定是無狀态的,對于一個浏覽器發出的多次請求,WEB伺服器無法區分 是不是來源于同一個浏覽器。 是以,為了實作會話,服務端需要一個會話辨別ID能儲存到浏覽器,讓它在後續的請求時都帶上這個會話辨別ID,以便讓服務端知道 某個請求屬于哪個會話,這樣便可以維護與會話相關的狀态資料。由于Cookie對于使用者來說,是個不可見的東西,而且每次請求都會傳遞到 服務端,是以它就是很理想的會話辨別ID的儲存容器。在Asp.net中,預設也就是使用Cookie來儲存這個ID的。注意:雖然Asp.net 2.0 也支援無Cookie的會話,但那種方式要修改URL,也有它的缺點,是以這種方法并沒有廣泛的使用。本文将不對這個話題做過多的分析, 就此略過無Cookie會話這種方式。

我們來看看Session是如何使用Cookie來儲存會話辨別ID的,在預設的Asp.net配置中,Web.config有着如下定義:

<sessionState mode="InProc" cookieName="ASP.NET_SessionId" cookieless="UseCookies"></sessionState>

      

如果我們執行以下操作:

Session["Key1"] = DateTime.Now;

      

此時,我們可以使用一些浏覽器提供的工具來檢視一下現在的Cookie情況。

細說Cookie

從圖檔上看,這個Cookie的名字就是我們在配置檔案中指出的名稱,我們可以修改一下配置檔案:

<sessionState cookieName="SK"></sessionState>

      

再來執行上面的寫Session的操作,然後看Cookie

細說Cookie

我們可以看到:SK的Cookie出現了。說明:在截圖時我把名稱為"ASP.NET_SessionId"的Cookie删除了。

通過上面示例,我們可以得到結論,Session的實作是與Cookie有關的,服務端需要将會話辨別ID儲存到Cookie中。

這裡再一次申明,除非你使用無Cookie的會話模式,否則Session是需要Cookie的支援。反過來,Cookie并不需要Session的支援。

Cookie在身份驗證中的應用

我想很多人都在Asp.net的開發中使用過Form身份認證。對于一個使用者請求, 我們可以在服務端很友善地判斷它是不是代表一個已登入使用者。

this.labStatus.Text = (Request.IsAuthenticated ? "已登入" : "未登入");

      

那麼,您有沒有好奇過:Asp.net是如何識别一個請求是不是一個已登入使用者發起的呢?說到這裡,我們就要從使用者登入說起了。 為了實作登入及Form認證方式,我們需要如下配置:

<authentication mode="Forms" >
    <forms name="UserStatus"></forms>
</authentication>
      

接下來,我們需要實作使用者登入邏輯。具體實作方式有很多,不過,最終的調用都是差不多的,如下代碼所示:

private void SetLogin()
{
    System.Web.Security.FormsAuthentication.SetAuthCookie("fish", false);
}
      

隻要執行了以上代碼,我們就可以看到,前面的判斷【Request.IsAuthenticated】傳回true,最終會顯示"已登入"。 為了探尋這個秘密,我們還是來看一下目前頁面的Cookie情況。

細說Cookie

果然,多出來一個Cookie,名稱與我在配置檔案中指定的名稱相同。我們再來看看如果登出目前登入會是什麼樣子的:

private void SetLogout()
{
    System.Web.Security.FormsAuthentication.SignOut();
}
      
細說Cookie

看到了嗎,名為"UserStatus"的Cookie不見了。此時如果你再去觀察【Request.IsAuthenticated】,可以發現它此時傳回 false。 或者,您也可以再試一次,登入後,直接删除名為"UserStatus"的Cookie,也能發現登入狀态将顯示"未登入"。 或許,您還是有點不清楚前面我調用【System.Web.Security.FormsAuthentication.SetAuthCookie("fish", false);】後,Asp.net做了些什麼, 回答這個問題其實很簡單:自己用Reflector.exe去看一下Asp.net的實作吧。

這裡為了更讓您能信服登入與Cookie有關,我将直接建立一個Cookie看一下 Asp.net能不能認可我建立的Cookie,并認為登入有效。請看代碼:

private void SetLogin()
{
    //System.Web.Security.FormsAuthentication.SetAuthCookie("fish", false);

    // 下面的代碼和上面的代碼在作用上是等效的。
    FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
        2, "fish", DateTime.Now, DateTime.Now.AddDays(30d), false, string.Empty);
    string str = FormsAuthentication.Encrypt(ticket);

    HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, str);
    Response.Cookies.Add(cookie);
}
      

如果執行這段代碼,您将發現:【Request.IsAuthenticated】傳回true,登入狀态會顯示"已登入"。

至此,我們可以得出一個結論: Form身份認證依賴Cookie,Asp.net就是每次檢查我們在配置檔案中指定的Cookie名稱,并解密這個Cookie來判斷目前請求使用者的登入狀态。

Cookie的安全狀況

從以上圖檔,您應該能發現:浏覽器能提供一些界面讓使用者清楚的觀察我們在服務端寫的Cookie, 甚至有些浏覽器還提供很友善的修改功能。如下圖所示:

細說Cookie

是以,我們在服務端寫代碼讀取Cookie時,尤其是涉及類型轉換、反序列化或者解密時,一定要注意這些操作都有可能會失敗。 而且上圖也清楚的反映了一個事實:Cookie中的值都是“一目了然”的,任何人都能看到它們。是以,我們盡量不要直接在Cookie中 儲存一些重要的或者敏感的内容。如果我們确實需要使用Cookie儲存一些重要的内容,但又不希望被他人看懂, 我們可以使用一些加密的方法來保護這些内容。

1. 對于一些重要性不高的内容,我們可以使用Base64之類的簡單處理方式來處理。

2. 對于重要性相對高一點的内容,我們可以利用.net提供的一些加密工具類,自己來設計加密方法來保護。不過, 密碼學與加密解密并不是很簡單的算法,是以,自己設計的加密方式可能不會很安全。

3. 重要的内容,我們可以使用.net提供的FormsAuthenticationTicket,FormsAuthentication來加密。我認為這種方式還是比較安全的。 畢竟前面我們也看過了,Asp.net的Form身份認證就是使用這種方式來加密使用者登入的身份辨別的,是以,如果這種方式不安全, 也就意味着Asp.net的身份認證也不安全了。 如果您使用這種方式來加密,那麼請注意:它産生的加密後文本還是比較大的, 前面我也提到過,每次請求時,浏覽器都會帶上與請求相比對的所有Cookie,是以,這種Cookie會對傳輸性能産生一定的影響, 是以,請小心使用,切記不可過多的使用。

這裡要補充一下:去年曾經出現過【Padding Oracle Attack】這個話題, 一些人甚至錯誤的認為是Asp.net加密方式不安全!如果您也是這樣認為的,那麼可以看一下這篇文章: 淺談這次ASP.NET的Padding Oracle Attack相關内容 ,以消除這個錯誤的認識。當然了,我們也可以從這個話題得到一些收獲:解密失敗時,不要給出過多的提示,就當沒有這個Cookie存在。

如何在C#發請的請求中使用Cookie

前面我們一直在談服務端與浏覽器中使用Cookie,其實浏覽器也是一個普通的應用程式,.net framework也提供一些類也能讓我們 直接發起HTTP請求,下面我們來看一下如何在C#發請的請求中使用Cookie ,其實也很簡單,主要是使用了CookieContainer類,請看以下示範代碼:

private static string SendHttpRequestGet(string url, Encoding encoding, 
            CookieContainer cookieContainer)
    {
        if( string.IsNullOrEmpty(url) )
            throw new ArgumentNullException("url");

        if( encoding == null )
            throw new ArgumentNullException("encoding");

        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
        request.Method = "GET";
        request.CookieContainer = cookieContainer;
        
        using( WebResponse response = request.GetResponse() ) {
            using( StreamReader reader = new StreamReader(response.GetResponseStream(), encoding) ) {
                return reader.ReadToEnd();
            }
        }
    }

    private void SendHttpDEMO()
    {
        StringBuilder sb = new StringBuilder();
        CookieContainer cookieContainer = new CookieContainer();

        string url = "http://www.taobao.com";
        SendHttpRequestGet(url, Encoding.Default, cookieContainer);

        // 後面可以繼續發起HTTP請求,此時将會包含上次從伺服器寫入的Cookie
        //SendHttpRequestGet("同域名下的其它URL", Encoding.Default, cookieContainer);

        // 至此,我們可以顯示取得了哪些Cookie
        CookieCollection cookies = cookieContainer.GetCookies(new Uri(url));
        if( cookies != null ) {
            foreach( System.Net.Cookie cookie in cookies )
                sb.AppendLine(cookie.ToString());
        }
        txtCookies.Text = sb.ToString();
    }
      

重構與使用總結

在前面的Asp.net示例代碼中,我一直使用.net提供的HttpCookie類來操作Cookie,是為了展示用原始的方式來使用Cookie, 這些代碼有點重複,也有點繁瑣, 為此,我提供了幾個簡單的方法可以更容易的使用Cookie,也算是對Cookie使用的一個總結。

/// <summary>
/// 用于友善使用Cookie的擴充工具類
/// </summary>
public static class CookieExtension
{
    // 我們可以為一些使用頻率高的類型寫專門的【讀取】方法

    /// <summary>
    /// 從一個Cookie中讀取字元串值。
    /// </summary>
    /// <param name="cookie"></param>
    /// <returns></returns>
    public static string GetString(this HttpCookie cookie)
    {
        if( cookie == null )
            return null;

        return cookie.Value;
    }

    /// <summary>
    /// 從一個Cookie中讀取 Int 值。
    /// </summary>
    /// <param name="cookie"></param>
    /// <param name="defaultVal"></param>
    /// <returns></returns>
    public static int ToInt(this HttpCookie cookie, int defaultVal)
    {
        if( cookie == null )
            return defaultVal;

        return cookie.Value.TryToInt(defaultVal);
    }

    /// <summary>
    /// 從一個Cookie中讀取值并轉成指定的類型
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="cookie"></param>
    /// <returns></returns>
    public static T ConverTo<T>(this HttpCookie cookie)
    {
        if( cookie == null )
            return default(T);

        return (T)Convert.ChangeType(cookie.Value, typeof(T));
    }

    /// <summary>
    /// 從一個Cookie中讀取【JSON字元串】值并反序列化成一個對象,用于讀取複雜對象
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="cookie"></param>
    /// <returns></returns>
    public static T FromJson<T>(this HttpCookie cookie)
    {
        if( cookie == null )
            return default(T);

        return cookie.Value.FromJson<T>();
    }


    /// <summary>
    /// 将一個對象寫入到Cookie
    /// </summary>
    /// <param name="obj"></param>
    /// <param name="name"></param>
    /// <param name="expries"></param>
    public static void WriteCookie(this object obj, string name, DateTime? expries)
    {
        if( obj == null )
            throw new ArgumentNullException("obj");

        if( string.IsNullOrEmpty(name) )
            throw new ArgumentNullException("name");
        

        HttpCookie cookie = new HttpCookie(name, obj.ToString());

        if( expries.HasValue )
            cookie.Expires = expries.Value;

        HttpContext.Current.Response.Cookies.Add(cookie);
    }

    /// <summary>
    /// 删除指定的Cookie
    /// </summary>
    /// <param name="name"></param>
    public static void DeleteCookie(string name)
    {
        if( string.IsNullOrEmpty(name) )
            throw new ArgumentNullException("name");

        HttpCookie cookie = new HttpCookie(name);

        // 删除Cookie,其實就是設定一個【過期的日期】
        cookie.Expires = new DateTime(1900, 1, 1);
        HttpContext.Current.Response.Cookies.Add(cookie);
    }
}

      

更完整的代碼可以從本文的示例代碼中獲得。(文章底部有下載下傳位址)

使用方式:

public static class TestClass
{
    public static void Write()
    {
        string str = "中國";
        int aa = 25;
        DisplaySettings setting = new DisplaySettings { Style = 3, Size = 50 };
        DateTime dt = new DateTime(2012, 1, 1, 12, 0, 0);

        str.WriteCookie("Key1", DateTime.Now.AddDays(1d));
        aa.WriteCookie("Key2", null);
        setting.ToJson().WriteCookie("Key3", null);
        dt.WriteCookie("Key4", null);
    }

    public static void Read()
    {
        HttpRequest request = HttpContext.Current.Request;

        string str = request.Cookies["Key1"].GetString();
        int num = request.Cookies["Key2"].ToInt(0);
        DisplaySettings setting = request.Cookies["Key3"].FromJson<DisplaySettings>();
        DateTime dt = request.Cookies["Key4"].ConverTo<DateTime>();
    }    
}

      

注意哦:以上代碼中都是直接使用字元串"Key"的形式,這種方式對于大一些的程式在後期可能會影響維護。

是以建議:将通路Cookie所使用的Key能有一個類來統一的定義,或者将讀寫操作包裝成一些屬性放在一個類中統一的管理。

public static class CookieValues
{
    // 建議把Cookie相關的參數放在一起,提供 get / set 屬性(或者方法)來通路,以避免"key"到處亂寫

    public static string AAA
    {
        get { return HttpContext.Current.Request.Cookies["Key1"].GetString(); }
    }
    public static int BBB
    {
        get { return HttpContext.Current.Request.Cookies["Key2"].ToInt(0); }
    }
    public static DisplaySettings CCC
    {
        get { return HttpContext.Current.Request.Cookies["Key3"].FromJson<DisplaySettings>(); }
    }
    public static DateTime DDD
    {
        get { return HttpContext.Current.Request.Cookies["Key4"].ConverTo<DateTime>(); }
    }
}
      

補充

根據一些朋友提供的回報,這裡再補充4個需要注意的地方:

1. 如果使用Form登入驗證且希望使用Cookie方式時,建議設定 cookieless="UseCookies", 因為這個參數的預設值是:cookieless="UseDeviceProfile",Asp.net可能會誤判。 dudu就吃過虧。

<authentication mode="Forms" >
    <forms name="MyCookieName" cookieless="UseCookies"></forms>
</authentication>
      

2. Cookie有3個屬性,一般我們可以不用設定,但它們的值可以在Web.config中指定預設值:

<httpCookies domain="www.123.com" httpOnlyCookies="true" requireSSL="false"/>
      

3. 雖然在寫Cookie時,我們可以設定name, value之外的其它屬性,但是在讀取時,是讀不到這些設定的。 其實在我的示例代碼中有展現,我前面也忘記了說明了。

4. HttpRequest.Cookies 與 HttpResponse.Cookies 會有關系(很奇怪吧)。

以下代碼示範了這個現象:

protected void Page_Load(object sender, EventArgs e)
{
    DateTime.Now.ToString().WriteCookie("t1", null);

    label1.Text = ShowAllCookies();

    Guid.NewGuid().ToString().WriteCookie("t2", null);

    // 如果去掉下面代碼,将會看到2個t1 
    Response.Cookies.Remove("t1");
    Response.Cookies.Remove("t2");
}

private string ShowAllCookies()
{
    StringBuilder sb = new StringBuilder();

    for( int i = 0; i < Request.Cookies.Count; i++ ) {
        HttpCookie cookie = Request.Cookies[i];
        sb.AppendFormat("{0}={1}<br />", cookie.Name, cookie.Value);
    }

    return sb.ToString();
}
      

上面的試驗代碼将會一直顯示 t1 的Cookie ,這裡就不再貼圖了。

轉自:http://www.cnblogs.com/fish-li/archive/2011/07/03/2096903.html