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 ,這裏就再也不貼圖了。
瀏覽器每次從新打開都會產生一個新的sessionid, 關閉後若是存放在服務器中的session尚未過時,那麼下次訪問仍是有效的。不過sessionid已經變了
我的看法