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,最後其實是通過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是放在請求頭中,發送到服務端的。如果你一直刷新頁面,就能發現, 每次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的代碼。
不過,這種方式產生的有些字符,比如【雙引號】,極少數瀏覽器(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>

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

注意哦:前面我們看到了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的名字就是我們在配置文件中指出的名稱,我們可以修改一下配置文件:

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

再來執行上面的寫Session的操作,然後看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,名稱與我在配置文件中指定的名稱相同。我們再來看看如果註銷當前登錄會是什麼樣子的:

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

看到了嗎,名爲"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保存一些重要的內容,但又不希望被他人看懂, 我們可以使用一些加密的方法來保護這些內容。

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 ,這裏就不再貼圖了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章