(轉(zhuǎn))細(xì)說Cookie

細(xì)說Cookie

閱讀目錄

開始

Cookie 概述

Cookie的寫、讀過程

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

Js中讀寫Cookie

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

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

Cookie的安全狀況

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

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

補(bǔ)充

Cookie雖然是個很簡單的東西摔寨,但它又是WEB開發(fā)中一個很重要的客戶端數(shù)據(jù)來源,而且它可以實(shí)現(xiàn)擴(kuò)展性很好的會話狀態(tài)鸯檬,

所以我認(rèn)為每個WEB開發(fā)人員都有必要對它有個清晰的認(rèn)識。本文將對Cookie這個話題做一個全面的描述,

也算是我對Cookie的認(rèn)識總結(jié)。

回到頂部

Cookie 概述

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

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

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

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

通過前面的內(nèi)容亡哄,我們了解到Cookie是用于維持服務(wù)端會話狀態(tài)的,通常由服務(wù)端寫入布疙,在后續(xù)請求中蚊惯,供服務(wù)端讀取。

下面本文將按這個過程看看Cookie是如何從服務(wù)端寫入灵临,最后如何傳到服務(wù)端以及如何讀取的截型。

回到頂部

Cookie的寫、讀過程

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

public sealed classHttpCookie{// 獲取或設(shè)置將此 Cookie 與其關(guān)聯(lián)的域。默認(rèn)值為當(dāng)前域顿涣。public stringDomain {get;set; }// 獲取或設(shè)置此 Cookie 的過期日期和時間(在客戶端)波闹。publicDateTimeExpires {get;set; }// 獲取一個值,通過該值指示 Cookie 是否具有子鍵涛碑。public boolHasKeys {get; }// 獲取或設(shè)置一個值精堕,該值指定 Cookie 是否可通過客戶端腳本訪問。

// 如果 Cookie 具有 HttpOnly 屬性且不能通過客戶端腳本訪問蒲障,則為 true歹篓;否則為 false。默認(rèn)為 false揉阎。public boolHttpOnly {get;set; }// 獲取或設(shè)置 Cookie 的名稱庄撮。public stringName {get;set; }// 獲取或設(shè)置要與當(dāng)前 Cookie 一起傳輸?shù)奶摂M路徑。默認(rèn)值為當(dāng)前請求的路徑毙籽。public stringPath {get;set; }// 獲取或設(shè)置一個值洞斯,該值指示是否使用安全套接字層 (SSL)(即僅通過 HTTPS)傳輸 Cookie。public boolSecure {get;set; }// 獲取或設(shè)置單個 Cookie 值坑赡。默認(rèn)值為空引用巡扇。public stringValue {get;set; }// 獲取單個 Cookie 對象所包含的鍵值對的集合。publicNameValueCollection Values {get; }// 獲取 System.Web.HttpCookie.Values 屬性的快捷方式垮衷。public string this[stringkey] {get;set; }}

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

HttpCookiecookie=newHttpCookie("MyCookieName","string value");Response.Cookies.Add(cookie);

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

從上圖,您應(yīng)該能發(fā)現(xiàn)甸昏,我們在服務(wù)端寫的Cookie顽分,最后其實(shí)是通過HTTP的響應(yīng)頭這種途徑發(fā)送到客戶端的。每一個寫入動作施蜜,都會產(chǎn)生一個【Set-Cookie】的響應(yīng)頭卒蘸。

瀏覽器正是在每次獲取請求的響應(yīng)后,檢查這些頭來接收Cookie的翻默。

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

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

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

從圖片中,我們可以發(fā)現(xiàn)肯污,Cookie是放在請求頭中翘单,發(fā)送到服務(wù)端的。如果你一直刷新頁面蹦渣,就能發(fā)現(xiàn)哄芜,每次HTTP請求,Cookie都會被發(fā)送柬唯。當(dāng)然了认臊,瀏覽器也不是發(fā)送它所接收到的所有Cookie,它會檢查當(dāng)前要請求的域名以及目錄权逗,只要這二項目與Cookie對應(yīng)的Domain和Path匹配美尸,才會發(fā)送冤议。對于Domain則是按照尾部匹配的原則進(jìn)行的斟薇。

所以,我在訪問 www.cnblogs.com 時恕酸,瀏覽器并不會將我在瀏覽 www.163.com 所接收到的 Cookie 發(fā)出去堪滨。

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

HttpCookiecookie=newHttpCookie("MyCookieName",null);cookie.Expires=newDateTime(1900,1,1);Response.Cookies.Add(cookie);

回到頂部

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

前面的示例代碼大致演示了Cookie的讀寫操作发笔。不過,我們平時可能希望將更復(fù)雜的【自定義類型】通過Cookie來保存凉翻,

那么又該如何操作呢了讨?對于這個問題,我們定義一個類型來看看如何處理。

public classDisplaySettings{public intStyle;public intSize;public override stringToString()? ? {return string.Format("Style = {0}, Size = {1}",this.Style,this.Size);? ? }? ? }

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

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

private voidWriteCookie_2a(){DisplaySettingssetting=newDisplaySettings{ Style=1, Size=24};HttpCookiecookie=newHttpCookie("DisplaySettings1");? ? cookie["Style"]=setting.Style.ToString();? ? cookie["Size"]=setting.Size.ToString();? ? Response.Cookies.Add(cookie);}private voidReadCookie_2a(){HttpCookiecookie=Request.Cookies["DisplaySettings1"];if( cookie==null)? ? ? ? labDisplaySettings1.Text="未定義";else{DisplaySettingssetting=newDisplaySettings();? ? ? ? setting.Style=cookie["Style"].TryToInt();? ? ? ? setting.Size=cookie["Size"].TryToInt();? ? ? ? labDisplaySettings1.Text=setting.ToString();? ? }}

方法-2旺垒,將對象JSON序列化為字符串。

private voidWriteCookie_2b(){DisplaySettingssetting=newDisplaySettings{ Style=2, Size=48};HttpCookiecookie=newHttpCookie("DisplaySettings2", setting.ToJson());? ? Response.Cookies.Add(cookie);}private voidReadCookie_2b(){HttpCookiecookie=Request.Cookies["DisplaySettings2"];if( cookie==null)? ? ? ? labDisplaySettings2.Text="未定義";else{DisplaySettingssetting=cookie.Value.FromJson();? ? ? ? labDisplaySettings2.Text=setting.ToString();? ? }}

這段代碼使用了我定義的二個擴(kuò)展方法苞冯。

///

///將一個對象序列化成 JSON 格式字符串///

///

/// public static stringToJson(this objectobj){if( obj==null)return string.Empty;JavaScriptSerializerjss=newJavaScriptSerializer();returnjss.Serialize(obj);}///

///從JSON字符串中反序列化對象///

///

///

/// public staticT FromJson(this stringcookie){if(string.IsNullOrEmpty(cookie) )return default(T);JavaScriptSerializerjss=newJavaScriptSerializer();returnjss.Deserialize(cookie);}

對于這二種方法袖牙,我個人更喜歡后者,因為它具有更好擴(kuò)展性:如果類型增加了成員舅锄,不需要修改讀寫Cookie的代碼鞭达。

不過,這種方式產(chǎn)生的有些字符皇忿,比如【雙引號】畴蹭,極少數(shù)瀏覽器(Opera)不支持,所以需要做UrlEncode或者Base64編碼處理鳍烁。

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

回到頂部

Js中讀寫Cookie

Cookie并非只能在服務(wù)端讀寫,在客戶端的瀏覽器中也可以實(shí)現(xiàn)對它的讀寫訪問爹梁。而且在JS中創(chuàng)建的Cookie對于服務(wù)端仍然有效(可見)右犹,

接下來我們來看看在JS中如何寫入Cookie,演示代碼將創(chuàng)建一個按鈕姚垃,并在點(diǎn)擊按鈕后寫入Cookie

functionWriteCookie() {varcookie="cookie_js=22222222; path=/";? ? ? ? document.cookie=cookie;? ? }

在JS中寫Cookie很簡單念链,只要給document.cookie賦值一個Cookie字符串即可,至于格式积糯,可以參考前面用Fiddle看到的結(jié)果掂墓。

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

functionReadCookie() {? ? ? ? alert(document.cookie);? ? }

仍然是訪問document.cookie看成,不過君编,這次我們得到卻是全部的Cookie值,每個Key/Value項用分號分開川慌,中間則用等號分開吃嘿。 所以偿荷,如果您想在JS中讀取Cookie,一定要按照這個規(guī)則來拆分并解析您要讀取的Cookie項唠椭。鑒于這樣的操作有些繁瑣跳纳,我們可以jquery.cookie.js插件來輕松完成這個功能,有興趣的朋友也可以看一下它是如何處理的贪嫂。這個插件的代碼比較少寺庄,這里就直接貼出,

注意哦:前面我們看到了HttpCookie有個HttpOnly屬性力崇,如果它為true斗塘,那么JS是讀不到那個Cookie的,也就是說:

我們?nèi)绻诜?wù)端生成的Cookie不希望在JS中能被訪問亮靴,可以在寫Cookie時馍盟,設(shè)置這個屬性。不過茧吊,通過一些工具贞岭,還是可以看到它們。

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

回到頂部

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

在Asp.net中,HttpContext, Page對象都有個Session的對象讶踪,我們可以使用它來方便地在服務(wù)端保存一些與會話相關(guān)的信息芯侥。

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

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

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

Session["Key1"]=DateTime.Now;

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

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

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

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

通過上面示例火鼻,我們可以得到結(jié)論室囊,Session的實(shí)現(xiàn)是與Cookie有關(guān)的,服務(wù)端需要將會話標(biāo)識ID保存到Cookie中魁索。

這里再一次申明波俄,除非你使用無Cookie的會話模式,否則Session是需要Cookie的支持蛾默。反過來懦铺,Cookie并不需要Session的支持。

回到頂部

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

我想很多人都在Asp.net的開發(fā)中使用過Form身份認(rèn)證支鸡。對于一個用戶請求冬念,

我們可以在服務(wù)端很方便地判斷它是不是代表一個已登錄用戶。

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

那么牧挣,您有沒有好奇過:Asp.net是如何識別一個請求是不是一個已登錄用戶發(fā)起的呢急前?說到這里,我們就要從用戶登錄說起了瀑构。

為了實(shí)現(xiàn)登錄及Form認(rèn)證方式裆针,我們需要如下配置:

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

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

只要執(zhí)行了以上代碼耘婚,我們就可以看到,前面的判斷【Request.IsAuthenticated】返回true陆赋,最終會顯示"已登錄"沐祷。

為了探尋這個秘密嚷闭,我們還是來看一下當(dāng)前頁面的Cookie情況。

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

private voidSetLogout(){? ? System.Web.Security.FormsAuthentication.SignOut();}

看到了嗎兢榨,名為"UserStatus"的Cookie不見了胜蛉。此時如果你再去觀察【Request.IsAuthenticated】,可以發(fā)現(xiàn)它此時返回 false色乾√懿幔或者,您也可以再試一次暖璧,登錄后案怯,直接刪除名為"UserStatus"的Cookie,也能發(fā)現(xiàn)登錄狀態(tài)將顯示"未登錄"澎办〕凹睿或許,您還是有點(diǎn)不清楚前面我調(diào)用【System.Web.Security.FormsAuthentication.SetAuthCookie("fish", false);】后局蚀,Asp.net做了些什么麦锯,回答這個問題其實(shí)很簡單:自己用Reflector.exe去看一下Asp.net的實(shí)現(xiàn)吧。

這里為了更讓您能信服登錄與Cookie有關(guān)琅绅,我將直接創(chuàng)建一個Cookie看一下Asp.net能不能認(rèn)可我創(chuàng)建的Cookie扶欣,并認(rèn)為登錄有效。請看代碼:

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

// 下面的代碼和上面的代碼在作用上是等效的千扶。FormsAuthenticationTicketticket=newFormsAuthenticationTicket(2,"fish",DateTime.Now,DateTime.Now.AddDays(30d),false,string.Empty);stringstr=FormsAuthentication.Encrypt(ticket);HttpCookiecookie=newHttpCookie(FormsAuthentication.FormsCookieName, str);? ? Response.Cookies.Add(cookie);}

如果執(zhí)行這段代碼料祠,您將發(fā)現(xiàn):【Request.IsAuthenticated】返回true,登錄狀態(tài)會顯示"已登錄"澎羞。

至此髓绽,我們可以得出一個結(jié)論:Form身份認(rèn)證依賴Cookie,Asp.net就是每次檢查我們在配置文件中指定的Cookie名稱妆绞,并解密這個Cookie來判斷當(dāng)前請求用戶的登錄狀態(tài)顺呕。

回到頂部

Cookie的安全狀況

從以上圖片,您應(yīng)該能發(fā)現(xiàn):瀏覽器能提供一些界面讓用戶清楚的觀察我們在服務(wù)端寫的Cookie括饶,

甚至有些瀏覽器還提供很方便的修改功能株茶。如下圖所示:

所以,我們在服務(wù)端寫代碼讀取Cookie時巷帝,尤其是涉及類型轉(zhuǎn)換忌卤、反序列化或者解密時扫夜,一定要注意這些操作都有可能會失敗楞泼。

而且上圖也清楚的反映了一個事實(shí):Cookie中的值都是“一目了然”的驰徊,任何人都能看到它們。所以堕阔,我們盡量不要直接在Cookie中

保存一些重要的或者敏感的內(nèi)容棍厂。如果我們確實(shí)需要使用Cookie保存一些重要的內(nèi)容,但又不希望被他人看懂超陆,

我們可以使用一些加密的方法來保護(hù)這些內(nèi)容牺弹。

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

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

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

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

回到頂部

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

前面我們一直在談服務(wù)端與瀏覽器中使用Cookie公你,其實(shí)瀏覽器也是一個普通的應(yīng)用程序,.net framework也提供一些類也能讓我們

直接發(fā)起HTTP請求假瞬,下面我們來看一下如何在C#發(fā)請的請求中使用Cookie 陕靠,其實(shí)也很簡單,主要是使用了CookieContainer類脱茉,請看以下演示代碼:

private static stringSendHttpRequestGet(stringurl,Encodingencoding,CookieContainercookieContainer)? ? {if(string.IsNullOrEmpty(url) )throw newArgumentNullException("url");if( encoding==null)throw newArgumentNullException("encoding");HttpWebRequestrequest=(HttpWebRequest)WebRequest.Create(url);? ? ? ? request.Method="GET";? ? ? ? request.CookieContainer=cookieContainer;using(WebResponseresponse=request.GetResponse() ) {using(StreamReaderreader=newStreamReader(response.GetResponseStream(), encoding) ) {returnreader.ReadToEnd();? ? ? ? ? ? }? ? ? ? }? ? }private voidSendHttpDEMO()? ? {StringBuildersb=newStringBuilder();CookieContainercookieContainer=newCookieContainer();stringurl="http://www.taobao.com";? ? ? ? SendHttpRequestGet(url,Encoding.Default, cookieContainer);// 后面可以繼續(xù)發(fā)起HTTP請求剪芥,此時將會包含上次從服務(wù)器寫入的Cookie

//SendHttpRequestGet("同域名下的其它URL", Encoding.Default, cookieContainer);

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

回到頂部

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

在前面的Asp.net示例代碼中琴许,我一直使用.net提供的HttpCookie類來操作Cookie粗俱,是為了展示用原始的方式來使用Cookie,

這些代碼有點(diǎn)重復(fù)虚吟,也有點(diǎn)繁瑣寸认,

為此,我提供了幾個簡單的方法可以更容易的使用Cookie串慰,也算是對Cookie使用的一個總結(jié)偏塞。

///

///用于方便使用Cookie的擴(kuò)展工具類/// public static classCookieExtension{// 我們可以為一些使用頻率高的類型寫專門的【讀取】方法///

///從一個Cookie中讀取字符串值。///

///

/// public static stringGetString(thisHttpCookiecookie)? ? {if( cookie==null)return null;returncookie.Value;? ? }///

///從一個Cookie中讀取 Int 值邦鲫。///

///

///

/// public static intToInt(thisHttpCookiecookie,intdefaultVal)? ? {if( cookie==null)returndefaultVal;returncookie.Value.TryToInt(defaultVal);? ? }///

///從一個Cookie中讀取值并轉(zhuǎn)成指定的類型///

///

///

/// public staticT ConverTo(thisHttpCookiecookie)? ? {if( cookie==null)return default(T);return(T)Convert.ChangeType(cookie.Value,typeof(T));? ? }///

///從一個Cookie中讀取【JSON字符串】值并反序列化成一個對象灸叼,用于讀取復(fù)雜對象///

///

///

/// public staticT FromJson(thisHttpCookiecookie)? ? {if( cookie==null)return default(T);returncookie.Value.FromJson();? ? }///

///將一個對象寫入到Cookie///

///

///

/// public static voidWriteCookie(this objectobj,stringname,DateTime?expries)? ? {if( obj==null)throw newArgumentNullException("obj");if(string.IsNullOrEmpty(name) )throw newArgumentNullException("name");HttpCookiecookie=newHttpCookie(name, obj.ToString());if( expries.HasValue )? ? ? ? ? ? cookie.Expires=expries.Value;HttpContext.Current.Response.Cookies.Add(cookie);? ? }///

///刪除指定的Cookie///

/// public static voidDeleteCookie(stringname)? ? {if(string.IsNullOrEmpty(name) )throw newArgumentNullException("name");HttpCookiecookie=newHttpCookie(name);// 刪除Cookie,其實(shí)就是設(shè)置一個【過期的日期】cookie.Expires=newDateTime(1900,1,1);HttpContext.Current.Response.Cookies.Add(cookie);? ? }}

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

使用方式:

public static classTestClass{public static voidWrite()? ? {stringstr="中國";intaa=25;DisplaySettingssetting=newDisplaySettings{ Style=3, Size=50};DateTimedt=newDateTime(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 voidRead()? ? {HttpRequestrequest=HttpContext.Current.Request;stringstr=request.Cookies["Key1"].GetString();intnum=request.Cookies["Key2"].ToInt(0);DisplaySettingssetting=request.Cookies["Key3"].FromJson();DateTimedt=request.Cookies["Key4"].ConverTo();? ? }? ? }

注意哦:以上代碼中都是直接使用字符串"Key"的形式古今,這種方式對于大一些的程序在后期可能會影響維護(hù)。

所以建議:將訪問Cookie所使用的Key能有一個類來統(tǒng)一的定義滔以,或者將讀寫操作包裝成一些屬性放在一個類中統(tǒng)一的管理捉腥。

public static classCookieValues{// 建議把Cookie相關(guān)的參數(shù)放在一起,提供 get / set 屬性(或者方法)來訪問你画,以避免"key"到處亂寫public static stringAAA? ? {get{returnHttpContext.Current.Request.Cookies["Key1"].GetString(); }? ? }public static intBBB? ? {get{returnHttpContext.Current.Request.Cookies["Key2"].ToInt(0); }? ? }public staticDisplaySettingsCCC? ? {get{returnHttpContext.Current.Request.Cookies["Key3"].FromJson(); }? ? }public staticDateTimeDDD? ? {get{returnHttpContext.Current.Request.Cookies["Key4"].ConverTo(); }? ? }}

回到頂部

補(bǔ)充

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

1. 如果使用Form登錄驗證且希望使用Cookie方式時,建議設(shè)置 cookieless="UseCookies"坏匪,因為這個參數(shù)的默認(rèn)值是:cookieless="UseDeviceProfile"拟逮,Asp.net可能會誤判。dudu就吃過虧适滓。

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

3. 雖然在寫Cookie時,我們可以設(shè)置name, value之外的其它屬性罚屋,但是在讀取時苦囱,是讀不到這些設(shè)置的。

其實(shí)在我的示例代碼中有體現(xiàn)沿后,我前面也忘記了說明了沿彭。

4. HttpRequest.Cookies 與 HttpResponse.Cookies 會有關(guān)系(很奇怪吧)朽砰。

以下代碼演示了這個現(xiàn)象:

protected voidPage_Load(objectsender,EventArgse){DateTime.Now.ToString().WriteCookie("t1",null);? ? label1.Text=ShowAllCookies();Guid.NewGuid().ToString().WriteCookie("t2",null);// 如果去掉下面代碼尖滚,將會看到2個t1Response.Cookies.Remove("t1");? ? Response.Cookies.Remove("t2");}private stringShowAllCookies(){StringBuildersb=newStringBuilder();for(inti=0; i", cookie.Name, cookie.Value);? ? }returnsb.ToString();}

上面的試驗代碼將會一直顯示 t1 的Cookie ,這里就不再貼圖了瞧柔。

本文的所有示例代碼可以點(diǎn)擊此處下載漆弄。

如果,您認(rèn)為閱讀這篇博客讓您有些收獲造锅,不妨點(diǎn)擊一下右下角的推薦按鈕撼唾。

如果,您希望更容易地發(fā)現(xiàn)我的新博客哥蔚,不妨點(diǎn)擊一下右下角的關(guān)注 Fish Li倒谷。

因為,我的寫作熱情也離不開您的肯定支持糙箍。

感謝您的閱讀渤愁,如果您對我的博客所講述的內(nèi)容有興趣,請繼續(xù)關(guān)注我的后續(xù)博客深夯,我是Fish Li 抖格。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市咕晋,隨后出現(xiàn)的幾起案子雹拄,更是在濱河造成了極大的恐慌,老刑警劉巖掌呜,帶你破解...
    沈念sama閱讀 206,013評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件滓玖,死亡現(xiàn)場離奇詭異,居然都是意外死亡质蕉,警方通過查閱死者的電腦和手機(jī)呢撞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來饰剥,“玉大人殊霞,你說我怎么就攤上這事√兀” “怎么了绷蹲?”我有些...
    開封第一講書人閱讀 152,370評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我祝钢,道長比规,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,168評論 1 278
  • 正文 為了忘掉前任拦英,我火速辦了婚禮蜒什,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘疤估。我一直安慰自己灾常,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,153評論 5 371
  • 文/花漫 我一把揭開白布铃拇。 她就那樣靜靜地躺著钞瀑,像睡著了一般。 火紅的嫁衣襯著肌膚如雪慷荔。 梳的紋絲不亂的頭發(fā)上雕什,一...
    開封第一講書人閱讀 48,954評論 1 283
  • 那天,我揣著相機(jī)與錄音显晶,去河邊找鬼贷岸。 笑死,一個胖子當(dāng)著我的面吹牛磷雇,可吹牛的內(nèi)容都是我干的偿警。 我是一名探鬼主播,決...
    沈念sama閱讀 38,271評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼倦春,長吁一口氣:“原來是場噩夢啊……” “哼户敬!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起睁本,我...
    開封第一講書人閱讀 36,916評論 0 259
  • 序言:老撾萬榮一對情侶失蹤尿庐,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后呢堰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體抄瑟,經(jīng)...
    沈念sama閱讀 43,382評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,877評論 2 323
  • 正文 我和宋清朗相戀三年枉疼,在試婚紗的時候發(fā)現(xiàn)自己被綠了皮假。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 37,989評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡骂维,死狀恐怖惹资,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情航闺,我是刑警寧澤褪测,帶...
    沈念sama閱讀 33,624評論 4 322
  • 正文 年R本政府宣布猴誊,位于F島的核電站,受9級特大地震影響侮措,放射性物質(zhì)發(fā)生泄漏懈叹。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,209評論 3 307
  • 文/蒙蒙 一分扎、第九天 我趴在偏房一處隱蔽的房頂上張望澄成。 院中可真熱鬧,春花似錦畏吓、人聲如沸墨状。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,199評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽歉胶。三九已至汛兜,卻和暖如春巴粪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背粥谬。 一陣腳步聲響...
    開封第一講書人閱讀 31,418評論 1 260
  • 我被黑心中介騙來泰國打工肛根, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人漏策。 一個月前我還...
    沈念sama閱讀 45,401評論 2 352
  • 正文 我出身青樓派哲,卻偏偏與公主長得像,于是被迫代替她去往敵國和親掺喻。 傳聞我的和親對象是個殘疾皇子芭届,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,700評論 2 345

推薦閱讀更多精彩內(nèi)容