閱讀目錄
Cookie是Web開發中一個很重要的客戶端數據來源,而且它可以實現擴展性很好的會話狀態。下面將對Cookie做一個全面描述:
回到頂部Cookie是什麼? Cookie 是伴隨著用戶請求和頁面在 Web 服務器和浏覽器之間傳遞一小段文本信息。Cookie 包含每次用戶訪問站點時 Web 應用程序都可以讀取的信息。
為什麼需要Cookie? 因為HTTP協議是無狀態的,WEB服務器無法區分浏覽器發出的多次請求是不是來源於同一個浏覽器。所以,需要額外的數據(Cookie)用於維護會話。
Cookie能做什麼? Cookie只是一段文本,故只能保存字符串並且會隨著每次請求被發送到服務器。由於浏覽器對Cookie的大小有限制,所以保存的Cookie不能太大。 Cookie的內容也是明文保存的,有些浏覽器提供界面修改,所以不適合保存重要的或者涉及隱私的內容或者做加密處理。
Cookie 的限制。 大多數浏覽器支持最大為 4096 字節的 Cookie。由於這限制了 Cookie 的大小,最好用 Cookie 來存儲少量數據,或者存儲用戶 ID 之類的標識符。用戶 ID 隨後便可用於標識用戶,以及從數據庫或其他數據源中讀取用戶信息。 浏覽器還限制站點可以在用戶計算機上存儲的 Cookie 的數量。大多數浏覽器只允許每個站點存儲 20 個 Cookie;如果試圖存儲更多 Cookie,則最舊的 Cookie 便會被丟棄。有些浏覽器還會對它們將接受的來自所有站點的 Cookie 總數作出絕對限制,通常為 300 個。
總結: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寫入浏覽器的過程:在項目中使用如下代碼向浏覽器寫入Cookie。簡單起見,這裡沒有設置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來保存, 那麼又該如何操作呢?對於這個問題,我們定義一個類型來看看如何處理。
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(); } }
這段代碼使用了我定義的二個擴展方法如下:
/// <summary> /// 將一個對象序列化成 JSON 格式字符串 /// </summary> /// <param name="obj"></param> /// <returns></returns> public static string ToJson(this object obj) { if( obj == null ) return string.Empty; JavaScriptSerializer jss = new JavaScriptSerializer(); return jss.Serialize(obj); } /// <summary> /// 從JSON字符串中反序列化對象 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="cookie"></param> /// <returns></returns> public static T FromJson<T>(this string cookie) { if( string.IsNullOrEmpty(cookie) ) return default(T); JavaScriptSerializer jss = new JavaScriptSerializer(); return jss.Deserialize<T>(cookie); }
對於這二種方法,我個人更喜歡後者,因為它具有更好擴展性:如果類型增加了成員,不需要修改讀寫Cookie的代碼。
不過,這種方式產生的有些字符,比如【雙引號】,極少數浏覽器(Opera)不支持,所以需要做UrlEncode或者Base64編碼處理。
同理,對於第一種方法,遇到Value有【雙引號】時,我們同樣需要做UrlEncode或者Base64編碼處理。
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插件來輕松完成這個功能,有興趣的朋友也可以看一下它是如何處理的。
/** * Create a cookie with the given name and value and other optional parameters. * * @example $.cookie('the_cookie', 'the_value'); * @desc Set the value of a cookie. * @example $.cookie('the_cookie', 'the_value', {expires: 7, path: '/', domain: 'jquery.com', secure: true}); * @desc Create a cookie with all available options. * @example $.cookie('the_cookie', 'the_value'); * @desc Create a session cookie. * @example $.cookie('the_cookie', null); * @desc Delete a cookie by passing null as value. * * @param String name The name of the cookie. * @param String value The value of the cookie. * @param Object options An object literal containing key/value pairs to provide optional cookie attributes. * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object. * If a negative value is specified (e.g. a date in the past), the cookie will be deleted. * If set to null or omitted, the cookie will be a session cookie and will not be retained * when the the browser exits. * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie). * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie). * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will * require a secure protocol (like HTTPS). * @type undefined * * @name $.cookie * @cat Plugins/Cookie * @author Klaus Hartl/[email protected] */ /** * Get the value of a cookie with the given name. * * @example $.cookie('the_cookie'); * @desc Get the value of a cookie. * * @param String name The name of the cookie. * @return The value of the cookie. * @type String * * @name $.cookie * @cat Plugins/Cookie * @author Klaus Hartl/[email protected] */ jQuery.cookie = function(name, value, options) { if (typeof value != 'undefined') { // name and value given, set cookie options = options || {}; if (value === null) { value = ''; options.expires = -1; } var expires = ''; if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) { var date; if (typeof options.expires == 'number') { date = new Date(); date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000)); } else { date = options.expires; } expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE } var path = options.path ? '; path=' + options.path : ''; var domain = options.domain ? '; domain=' + options.domain : ''; var secure = options.secure ? '; secure' : ''; document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join(''); } else { // only name given, get cookie(According to the name to get the value of cookie ) var cookieValue = null; if (document.cookie && document.cookie != '') { var cookies = document.cookie.split(';');//Get All Cookie Collections,then to foreach every one for (var i = 0; i < cookies.length; i++) { var cookie = jQuery.trim(cookies[i]); // Does this cookie string begin with the name we want?(The function is so distinct,So I like it!It doesn't need more judgement.) if (cookie.substring(0, name.length + 1) == (name + '=')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; } };
注意哦:前面我們看到了HttpCookie有個HttpOnly屬性,如果它為true,那麼JS是讀不到那個Cookie的,也就是說: 我們如果在服務端生成的Cookie不希望在JS中能被訪問,可以在寫Cookie時,設置這個屬性。不過,通過一些工具,還是可以看到它們。
接下來,我們再來看看Asp.net中Cookie有哪些應用。
回到頂部在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的支持。
我想很多人都在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保存一些重要的內容,但又不希望被他人看懂, 我們可以使用一些加密的方法來保護這些內容。
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存在。
回到頂部前面我們一直在談服務端與浏覽器中使用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
用session就可以
(個人理解,僅供參考) 先給大家展示一張PHP處理session的應用架構圖: 我們知道,在同一次會話中,所有的session信息都會保存在一個文件名類似為sess_4e28e33e7c5d3371c173b28163afd8bd(sess_加32位隨機字母與數字組成的字符串)的自動隨機命名的文件信息中。因為http會為每一次php頁面中的session_start()請求都會創建一個sessionID,而又開啟了cookie後,浏覽器返回的Cookie:PHPSESSID(可以使用網頁數據分析工具HttpWatch抓取查看)會與session_start()創建的sessionID相等,信息及時銜接,所以在服務器端一次會話只會創建一個session文件,該session文件包含了所有當前會話的信息。 禁用cookie後,浏覽器的確會在服務器端創建一個session文件,這時候這個session文件也會將PHPSESSID信息返回給浏覽器,但是這個時候浏覽器已經不能接收這樣的信息了。這意味著,當浏覽器再次發送另外的session_start()信息的時候就不會帶PHPSESSID的值了,因此,當前頁面就無法找到原來已經創建的session文件,就會重新自動創建新的session文件。如此一來,每次執行session_start()都會有新的session文件產生,即一次會話就會產生多個session文件,會話信息就不能實現共享。 那麼,如何解決這個問題呢?只要把sessionID傳遞回服務器即可。這裡提供下面三種方法。 1.在每個超鏈接上添加一個PHPSESSID=sessionID值,同時在每個頁面加上類似如下(偽)代碼:if(isset($_GET['PHPSESSID'])){ //設置session_id session_id($_GET['PHPSESSID']); } session_start(); . . . 2.使用系統常量SID:在超鏈接action header('Location:xx')可以直接拼接SID常量如echo "細說PHP"; 3. 直接配置php.ini文件。將php.ini文件裡的session.use_trans_sid= 0設為1,重啟apache即可生效(這樣在href action header提供的地址後面會自動加SID,但是js的跳轉不會自動加SID)。