乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      細(xì)說Cookie

       賈朋亮博客 2011-07-17

      Cookie雖然是個(gè)很簡單的東西,但它又是WEB開發(fā)中一個(gè)很重要的客戶端數(shù)據(jù)來源,而且它可以實(shí)現(xiàn)擴(kuò)展性很好的會(huì)話狀態(tài),所以我認(rèn)為每個(gè)WEB開發(fā)人員都有必要對它有個(gè)清晰的認(rèn)識(shí)。本文將對Cookie這個(gè)話題做一個(gè)全面的描述,也算是本人對Cookie的認(rèn)識(shí)總結(jié)。

      Cookie 概述

      Cookie是什么? Cookie 是一小段文本信息,伴隨著用戶請求和頁面在 Web 服務(wù)器和瀏覽器之間傳遞。Cookie 包含每次用戶訪問站點(diǎn)時(shí) Web 應(yīng)用程序都可以讀取的信息。

      為什么需要Cookie? 因?yàn)镠TTP協(xié)議是無狀態(tài)的,對于一個(gè)瀏覽器發(fā)出的多次請求,WEB服務(wù)器無法區(qū)分是不是來源于同一個(gè)瀏覽器。所以,需要額外的數(shù)據(jù)用于維護(hù)會(huì)話。 Cookie 正是這樣的一段隨HTTP請求一起被傳遞的額外數(shù)據(jù)。

      Cookie能做什么? Cookie只是一段文本,所以它只能保存字符串。而且瀏覽器對它有大小限制以及它會(huì)隨著每次請求被發(fā)送到服務(wù)器,所以應(yīng)該保證它不要太大。 Cookie的內(nèi)容也是明文保存的,有些瀏覽器提供界面修改,所以,不適合保存重要的或者涉及隱私的內(nèi)容。

      Cookie 的限制。 大多數(shù)瀏覽器支持最大為 4096 字節(jié)的 Cookie。由于這限制了 Cookie 的大小,最好用 Cookie 來存儲(chǔ)少量數(shù)據(jù),或者存儲(chǔ)用戶 ID 之類的標(biāo)識(shí)符。用戶 ID 隨后便可用于標(biāo)識(shí)用戶,以及從數(shù)據(jù)庫或其他數(shù)據(jù)源中讀取用戶信息。瀏覽器還限制站點(diǎn)可以在用戶計(jì)算機(jī)上存儲(chǔ)的 Cookie 的數(shù)量。大多數(shù)瀏覽器只允許每個(gè)站點(diǎn)存儲(chǔ) 20 個(gè) Cookie;如果試圖存儲(chǔ)更多 Cookie,則最舊的 Cookie 便會(huì)被丟棄。有些瀏覽器還會(huì)對它們將接受的來自所有站點(diǎn)的 Cookie 總數(shù)作出絕對限制,通常為 300 個(gè)。

      通過前面的內(nèi)容,我們了解到Cookie是用于維持服務(wù)端會(huì)話狀態(tài)的,通常由服務(wù)端寫入,在后續(xù)請求中,供服務(wù)端讀取。下面本文將按這個(gè)過程看看Cookie是如何從服務(wù)端寫入,最后如何傳到服務(wù)端以及如何讀取的。

      Cookie的寫、讀過程

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

      public sealed class HttpCookie
      {
      // 獲取或設(shè)置將此 Cookie 與其關(guān)聯(lián)的域。默認(rèn)值為當(dāng)前域。
      public string Domain { get; set; }
      // 獲取或設(shè)置此 Cookie 的過期日期和時(shí)間(在客戶端)。
      public DateTime Expires { get; set; }
      // 獲取一個(gè)值,通過該值指示 Cookie 是否具有子鍵。
      public bool HasKeys { get; }
      // 獲取或設(shè)置一個(gè)值,該值指定 Cookie 是否可通過客戶端腳本訪問。
      // 如果 Cookie 具有 HttpOnly 屬性且不能通過客戶端腳本訪問,則為 true;否則為 false。默認(rèn)為 false。
      public bool HttpOnly { get; set; }
      // 獲取或設(shè)置 Cookie 的名稱。
      public string Name { get; set; }
      // 獲取或設(shè)置要與當(dāng)前 Cookie 一起傳輸?shù)奶摂M路徑。默認(rèn)值為當(dāng)前請求的路徑。
      public string Path { get; set; }
      // 獲取或設(shè)置一個(gè)值,該值指示是否使用安全套接字層 (SSL)(即僅通過 HTTPS)傳輸 Cookie。
      public bool Secure { get; set; }
      // 獲取或設(shè)置單個(gè) Cookie 值。默認(rèn)值為空引用。
      public string Value { get; set; }
      // 獲取單個(gè) Cookie 對象所包含的鍵值對的集合。
      public NameValueCollection Values { get; }
      // 獲取 System.Web.HttpCookie.Values 屬性的快捷方式。
      public string this[string key] { get; set; }
      }
      

      Cookie寫入瀏覽器的過程:我們可以使用如下代碼在Asp.net項(xiàng)目中寫一個(gè)Cookie 并發(fā)送到客戶端的瀏覽器(為了簡單我沒有設(shè)置其它屬性)。

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

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

      從上圖,您應(yīng)該能發(fā)現(xiàn),我們在服務(wù)端寫的Cookie,最后其實(shí)是通過HTTP的響應(yīng)頭這種途徑發(fā)送到客戶端的。每一個(gè)寫入動(dòng)作,都會(huì)產(chǎn)生一個(gè)【Set-Cookie】的響應(yīng)頭。
      瀏覽器正是在每次獲取請求的響應(yīng)后,檢查這些頭來接收Cookie的。

      Asp.net獲取Cookie的過程:我們可以使用如下代碼在Asp.net項(xiàng)目中讀取一個(gè)Cookie

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

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

      從圖片中,我們可以發(fā)現(xiàn),Cookie是放在請求頭中,發(fā)送到服務(wù)端的。如果你一直刷新頁面,就能發(fā)現(xiàn), 每次HTTP請求,Cookie都會(huì)被發(fā)送。當(dāng)然了,瀏覽器也不是發(fā)送它所接收到的所有Cookie,它會(huì)檢查當(dāng)前要請求的域名以及目錄,只要這二項(xiàng)目與Cookie對應(yīng)的Domain和Path匹配,才會(huì)發(fā)送。對于Domain則是按照尾部匹配的原則進(jìn)行的。
      所以,我在訪問 www.cnblogs.com 時(shí),瀏覽器并不會(huì)將我在瀏覽 www.163.com 所接收到的 Cookie 發(fā)出去。

      刪除Cookie:其實(shí)就是在寫Cookie時(shí),設(shè)置Expires為一個(gè)【早于現(xiàn)在時(shí)間的時(shí)間】。也就是:設(shè)置此Cookie已經(jīng)過期,瀏覽器接收到這個(gè)Cookie時(shí),便會(huì)刪除它們。

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

      使用Cookie保存復(fù)雜對象

      前面的示例代碼大致演示了Cookie的讀寫操作。不過,我們平時(shí)可能希望將更復(fù)雜的【自定義類型】通過Cookie來保存,那么又該如何操作呢?對于這個(gè)問題,我們定義一個(gè)類型來看看如何處理。

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

      上面的代碼,我定義一個(gè)類型,用于保存用戶在瀏覽頁面時(shí)的顯示設(shè)置。接下來,我將介紹二種方法在Cookie中保存并讀取它們。

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

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

      這段代碼使用了我定義的二個(gè)擴(kuò)展方法。點(diǎn)擊此處展開

      對于這二種方法,我個(gè)人更喜歡后者,因?yàn)樗哂懈脭U(kuò)展性:如果類型增加了成員,不需要修改讀寫Cookie的代碼。
      不過,這種方式產(chǎn)生的有些字符,比如【雙引號(hào)】,極少數(shù)瀏覽器(Opera)不支持,所以需要做UrlEncode或者Base64編碼處理。
      同理,對于第一種方法,遇到Value有【雙引號(hào)】時(shí),我們同樣需要做UrlEncode或者Base64編碼處理。

      Js中讀寫Cookie

      Cookie并非只能在服務(wù)端讀寫,在客戶端的瀏覽器中也可以實(shí)現(xiàn)對它的讀寫訪問。而且在JS中創(chuàng)建的Cookie對于服務(wù)端仍然有效(可見),接下來我們來看看在JS中如何寫入Cookie,演示代碼將創(chuàng)建一個(gè)按鈕,并在點(diǎn)擊按鈕后寫入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賦值一個(gè)Cookie字符串即可,至于格式,可以參考前面用Fiddle看到的結(jié)果。

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

      <input type="button" onclick="ReadCookie();" value="ReadCookie" />
      <script type="text/javascript">
      function ReadCookie() {
      alert(document.cookie);
      }
      </script>
      

      仍然是訪問document.cookie,不過,這次我們得到卻是全部的Cookie值,每個(gè)Key/Value項(xiàng)用分號(hào)分開,中間則用等號(hào)分開。 所以,如果您想在JS中讀取Cookie,一定要按照這個(gè)規(guī)則來拆分并解析您要讀取的Cookie項(xiàng)。鑒于這樣的操作有些繁瑣,我們可以jquery.cookie.js插件來輕松完成這個(gè)功能,有興趣的朋友也可以看一下它是如何處理的。這個(gè)插件的代碼比較少,這里就直接貼出, 點(diǎn)擊此處展開

      注意哦:前面我們看到了HttpCookie有個(gè)HttpOnly屬性,如果它為true,那么JS是讀不到那個(gè)Cookie的,也就是說:我們?nèi)绻诜?wù)端生成的Cookie不希望在JS中能被訪問,可以在寫Cookie時(shí),設(shè)置這個(gè)屬性。不過,通過一些工具,還是可以看到它們。

      接下來,我們再來看看Asp.net中Cookie有哪些應(yīng)用。

      Cookie在Session中的應(yīng)用

      在Asp.net中,HttpContext, Page對象都有個(gè)Session的對象,我們可以使用它來方便地在服務(wù)端保存一些與會(huì)話相關(guān)的信息。
      前面我們也提到過,HTTP協(xié)議是無狀態(tài)的,對于一個(gè)瀏覽器發(fā)出的多次請求,WEB服務(wù)器無法區(qū)分 是不是來源于同一個(gè)瀏覽器。 所以,為了實(shí)現(xiàn)會(huì)話,服務(wù)端需要一個(gè)會(huì)話標(biāo)識(shí)ID能保存到瀏覽器,讓它在后續(xù)的請求時(shí)都帶上這個(gè)會(huì)話標(biāo)識(shí)ID,以便讓服務(wù)端知道某個(gè)請求屬于哪個(gè)會(huì)話,這樣便可以維護(hù)與會(huì)話相關(guān)的狀態(tài)數(shù)據(jù)。由于Cookie對于用戶來說,是個(gè)不可見的東西,而且每次請求都會(huì)傳遞到服務(wù)端,所以它就是很理想的會(huì)話標(biāo)識(shí)ID的保存容器。在Asp.net中,默認(rèn)也就是使用Cookie來保存這個(gè)ID的。注意:雖然Asp.net 2.0 也支持無Cookie的會(huì)話,但那種方式要修改URL,也有它的缺點(diǎn),因此這種方法并沒有廣泛的使用。本文將不對這個(gè)話題做過多的分析,就此略過無Cookie會(huì)話這種方式。

      我們來看看Session是如何使用Cookie來保存會(huì)話標(biāo)識(shí)ID的,在默認(rèn)的Asp.net配置中,Web.config有著如下定義:

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

      如果我們執(zhí)行以下操作:

      Session["Key1"] = DateTime.Now;
      

      此時(shí),我們可以使用一些瀏覽器提供的工具來查看一下現(xiàn)在的Cookie情況。

      從圖片上看,這個(gè)Cookie的名字就是我們在配置文件中指出的名稱,我們可以修改一下配置文件:

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

      再來執(zhí)行上面的寫Session的操作,然后看Cookie

      我們可以看到:SK的Cookie出現(xiàn)了。說明:在截圖時(shí)我把名稱為"ASP.NET_SessionId"的Cookie刪除了。

      通過上面示例,我們可以得到結(jié)論,Session的實(shí)現(xiàn)是與Cookie有關(guān)的,服務(wù)端需要將會(huì)話標(biāo)識(shí)ID保存到Cookie中。
      這里再一次申明,除非你使用無Cookie的會(huì)話模式,否則Session是需要Cookie的支持。反過來,Cookie并不需要Session的支持。

      Cookie在身份驗(yàn)證中的應(yīng)用

      我想很多人都在Asp.net的開發(fā)中使用過Form身份認(rèn)證。對于一個(gè)用戶請求,我們可以在服務(wù)端很方便地判斷它是不是代表一個(gè)已登錄用戶。

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

      那么,您有沒有好奇過:Asp.net是如何識(shí)別一個(gè)請求是不是一個(gè)已登錄用戶發(fā)起的呢?說到這里,我們就要從用戶登錄說起了。為了實(shí)現(xiàn)登錄及Form認(rèn)證方式,我們需要如下配置:

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

      接下來,我們需要實(shí)現(xiàn)用戶登錄邏輯。具體實(shí)現(xiàn)方式有很多,不過,最終的調(diào)用都是差不多的,如下代碼所示:

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

      只要執(zhí)行了以上代碼,我們就可以看到,前面的判斷【Request.IsAuthenticated】返回true,最終會(huì)顯示"已登錄"。為了探尋這個(gè)秘密,我們還是來看一下當(dāng)前頁面的Cookie情況。

      果然,多出來一個(gè)Cookie,名稱與我在配置文件中指定的名稱相同。我們再來看看如果注銷當(dāng)前登錄會(huì)是什么樣子的:

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

      看到了嗎,名為"UserStatus"的Cookie不見了。此時(shí)如果你再去觀察【Request.IsAuthenticated】,可以發(fā)現(xiàn)它此時(shí)返回 false?;蛘?,您也可以再試一次,登錄后,直接刪除名為"UserStatus"的Cookie,也能發(fā)現(xiàn)登錄狀態(tài)將顯示"未登錄"。或許,您還是有點(diǎn)不清楚前面我調(diào)用【System.Web.Security.FormsAuthentication.SetAuthCookie("fish", false);】后,Asp.net做了些什么,回答這個(gè)問題其實(shí)很簡單:自己用Reflector.exe去看一下Asp.net的實(shí)現(xiàn)吧。
      這里為了更讓您能信服登錄與Cookie有關(guān),我將直接創(chuàng)建一個(gè)Cookie看一下 Asp.net能不能認(rèn)可我創(chuàng)建的Cookie,并認(rèn)為登錄有效。請看代碼:

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

      如果執(zhí)行這段代碼,您將發(fā)現(xiàn):【Request.IsAuthenticated】返回true,登錄狀態(tài)會(huì)顯示"已登錄"。
      至此,我們可以得出一個(gè)結(jié)論: Form身份認(rèn)證依賴Cookie,Asp.net就是每次檢查我們在配置文件中指定的Cookie名稱,并解密這個(gè)Cookie來判斷當(dāng)前請求用戶的登錄狀態(tài)。

      Cookie的安全狀況

      從以上圖片,您應(yīng)該能發(fā)現(xiàn):瀏覽器能提供一些界面讓用戶清楚的觀察我們在服務(wù)端寫的Cookie,甚至有些瀏覽器還提供很方便的修改功能。如下圖所示:

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

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

      2. 對于重要性相對高一點(diǎn)的內(nèi)容,我們可以利用.net提供的一些加密工具類,自己來設(shè)計(jì)加密方法來保護(hù)。不過,密碼學(xué)與加密解密并不是很簡單的算法,因此,自己設(shè)計(jì)的加密方式可能不會(huì)很安全。

      3. 重要的內(nèi)容,我們可以使用.net提供的FormsAuthenticationTicket,FormsAuthentication來加密。我認(rèn)為這種方式還是比較安全的。畢竟前面我們也看過了,Asp.net的Form身份認(rèn)證就是使用這種方式來加密用戶登錄的身份標(biāo)識(shí)的,所以,如果這種方式不安全,也就意味著Asp.net的身份認(rèn)證也不安全了。如果您使用這種方式來加密,那么請注意:它產(chǎn)生的加密后文本還是比較大的,前面我也提到過,每次請求時(shí),瀏覽器都會(huì)帶上與請求相匹配的所有Cookie,因此,這種Cookie會(huì)對傳輸性能產(chǎn)生一定的影響,所以,請小心使用,切記不可過多的使用。

      這里要補(bǔ)充一下:去年曾經(jīng)出現(xiàn)過【Padding Oracle Attack】這個(gè)話題,一些人甚至錯(cuò)誤的認(rèn)為是Asp.net加密方式不安全!如果您也是這樣認(rèn)為的,那么可以看一下這篇文章: 淺談這次ASP.NET的Padding Oracle Attack相關(guān)內(nèi)容 ,以消除這個(gè)錯(cuò)誤的認(rèn)識(shí)。當(dāng)然了,我們也可以從這個(gè)話題得到一些收獲:解密失敗時(shí),不要給出過多的提示,就當(dāng)沒有這個(gè)Cookie存在。

      如何在C#發(fā)請的請求中使用Cookie

      前面我們一直在談服務(wù)端與瀏覽器中使用Cookie,其實(shí)瀏覽器也是一個(gè)普通的應(yīng)用程序,.net framework也提供一些類也能讓我們直接發(fā)起HTTP請求,下面我們來看一下如何在C#發(fā)請的請求中使用Cookie ,其實(shí)也很簡單,主要是使用了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);
      // 后面可以繼續(xù)發(fā)起HTTP請求,此時(shí)將會(huì)包含上次從服務(wù)器寫入的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();
      }
      

      重構(gòu)與使用總結(jié)

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

      /// <summary>
      /// 用于方便使用Cookie的擴(kuò)展工具類
      /// </summary>
      public static class CookieExtension
      {
      // 我們可以為一些使用頻率高的類型寫專門的【讀取】方法
      /// <summary>
      /// 從一個(gè)Cookie中讀取字符串值。
      /// </summary>
      /// <param name="cookie"></param>
      /// <returns></returns>
      public static string GetString(this HttpCookie cookie)
      {
      if( cookie == null )
      return null;
      return cookie.Value;
      }
      /// <summary>
      /// 從一個(gè)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>
      /// 從一個(gè)Cookie中讀取值并轉(zhuǎn)成指定的類型
      /// </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>
      /// 從一個(gè)Cookie中讀取【JSON字符串】值并反序列化成一個(gè)對象,用于讀取復(fù)雜對象
      /// </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>
      /// 將一個(gè)對象寫入到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,其實(shí)就是設(shè)置一個(gè)【過期的日期】
      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"的形式,這種方式對于大一些的程序在后期可能會(huì)影響維護(hù)。
      所以建議:將訪問Cookie所使用的Key能有一個(gè)類來統(tǒng)一的定義,或者將讀寫操作包裝成一些屬性放在一個(gè)類中統(tǒng)一的管理。

      public static class CookieValues
      {
      // 建議把Cookie相關(guān)的參數(shù)放在一起,提供 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>(); }
      }
      }
      

      補(bǔ)充

      根據(jù)一些朋友提供的反饋,這里再補(bǔ)充4個(gè)需要注意的地方:

      1. 如果使用Form登錄驗(yàn)證且希望使用Cookie方式時(shí),建議設(shè)置 cookieless="UseCookies",因?yàn)檫@個(gè)參數(shù)的默認(rèn)值是:cookieless="UseDeviceProfile",Asp.net可能會(huì)誤判。 dudu就吃過虧。

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

      2. Cookie有3個(gè)屬性,一般我們可以不用設(shè)置,但它們的值可以在Web.config中指定默認(rèn)值:

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

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

      4. HttpRequest.Cookies 與 HttpResponse.Cookies 有時(shí)會(huì)有關(guān)系(很奇怪吧)。
      關(guān)系發(fā)生在請求過程中第一次訪問HttpRequest.Cookies時(shí),將會(huì)把HttpResponse.Cookies的Cookie也填充進(jìn)來。以下代碼演示了這個(gè)現(xiàn)象:

      protected void Page_Load(object sender, EventArgs e)
      {
      DateTime.Now.ToString().WriteCookie("t1", null);
      label1.Text = ShowAllCookies();
      Guid.NewGuid().ToString().WriteCookie("t2", null);
      // 如果去掉下面代碼,將會(huì)看到2個(gè)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();
      }
      

      建議在做這個(gè)試驗(yàn)時(shí),在web.config中做如下設(shè)置,因?yàn)橛行㎝odule可能會(huì)有訪問Cookie的操作,所以可能會(huì)影響試驗(yàn)結(jié)果。

      <httpModules>
      <clear/>
      </httpModules>
      

      上面的試驗(yàn)代碼將會(huì)一直顯示 t1 的Cookie ,這里就不再貼圖了。

       

       

       

      好了,就到這里吧。本文的所有示例代碼可以點(diǎn)擊此處下載。

      二天時(shí)間寫此文,希望能給您一點(diǎn)收獲。如果認(rèn)為此文對您有幫助,別忘了支持一下哦。

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多