Cookies揭祕 [Asp.Net, Javascript]

一,前言

Cookies想必全部人都瞭解, 可是未必全部人都精通。本文講解了Cookies的各方面知識, 而且提出來了最佳實踐。這是筆者在平常工做中的積累和沉澱。javascript

 

二,基礎知識

1.什麼是Cookies

Cookie 是一小段文本信息,伴隨着用戶請求和頁面在 Web 服務器和瀏覽器之間傳遞。Cookie 包含每次用戶訪問站點時 Web 應用程序均可以讀取的信息。html

例如,若是在用戶請求站點中的頁面時應用程序發送給該用戶的不只僅是一個頁面,還有一個包含日期和時間的 Cookie,用戶的瀏覽器在得到頁面的同時還得到了該 Cookie,並將它存儲在用戶硬盤上的某個文件夾中。java

之後,若是該用戶再次請求您站點中的頁面,當該用戶輸入 URL 時,瀏覽器便會在本地硬盤上查找與該 URL 關聯的 Cookie。若是該 Cookie 存在,瀏覽器便將該 Cookie 與頁請求一塊兒發送到您的站點。而後,應用程序即可以肯定該用戶上次訪問站點的日期和時間。您可使用這些信息向用戶顯示一條消息,也能夠檢查到期日期。jquery

Cookie 與網站關聯,而不是與特定的頁面關聯。所以,不管用戶請求站點中的哪個頁面,瀏覽器和服務器都將交換 Cookie 信息。用戶訪問不一樣站點時,各個站點均可能會向用戶的瀏覽器發送一個 Cookie;瀏覽器會分別存儲全部 Cookie。windows

Cookie 幫助網站存儲有關訪問者的信息。通常來講,Cookie 是一種保持 Web 應用程序連續性(即執行狀態管理)的方法。除短暫的實際交換信息的時間外,瀏覽器和 Web 服務器間都是斷開鏈接的。對於用戶向 Web 服務器發出的每一個請求,Web 服務器都會單獨處理。可是在不少狀況下,Web 服務器在用戶請求頁時識別出用戶會十分有用。例如,購物站點上的 Web 服務器跟蹤每位購物者,這樣站點就能夠管理購物車和其餘的用戶特定信息。所以,Cookie 能夠做爲一種名片,提供相關的標識信息幫助應用程序肯定如何繼續執行。瀏覽器

使用 Cookie 可以達到多種目的,全部這些目的都是爲了幫助網站記住用戶。例如,一個實施民意測驗的站點能夠簡單地將 Cookie 做爲一個 Boolean 值,用它來指示用戶的瀏覽器是否已參與了投票,這樣用戶便沒法進行第二次投票。要求用戶登陸的站點則能夠經過 Cookie 來記錄用戶已經登陸,這樣用戶就沒必要每次都輸入憑據。服務器

2.Cookies如何存儲

Cookies保存在用戶的本地機器上,不一樣的瀏覽器存儲在不一樣的文件夾中,而且按照域名分別保存。即網站之間的Cookies不會彼此覆蓋。cookie

IE瀏覽器的用戶能夠經過在本地的文檔中找到Cookies的txt文件, 不一樣操做系統的位置不一樣,windows server 2003/xp都保存在:app

C:\Documents and Settings\Administrator\Cookies 文件夾下。asp.net

其中名稱txt按照域名保存,好比localhost域下的cookies爲:

administrator@localhost[1].txt 或者 administrator@localhost[2].txt

其中後面的[1]和[2]是隨着每次保存交替變化的。

3.Cookies如何傳遞

Cookies的信息是在Web服務器和瀏覽器之間傳遞的。保存在Http請求中。

(1)請求頁面

在請求一個頁面的Http頭中,會將屬於此頁面的本地Cookies信息加在Http頭中,注意下面加粗的部分:

GET /Cookies/Test.aspx HTTP/1.1 
Host: localhost:1335 
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.2; zh-CN; rv:1.9.1.1) Gecko/20090715 Firefox/3.5.1 GTB5 (.NET CLR 3.5.30729) 
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 
Accept-Language: zh-cn,zh;q=0.5 
Accept-Encoding: gzip,deflate 
Accept-Charset: GB2312,utf-8;q=0.7,*;q=0.7 
Keep-Alive: 300 
Connection: keep-alive 
Cookie: My.Common.TestCookieInfo=Pkid=999&TestValue=aaabbbcccdddeee 

(2)頁面響應

若是頁面要求寫入Cookies信息,則返回的Http以下,注意加粗的部分:

HTTP/1.x 200 OK 
Server: ASP.NET Development Server/9.0.0.0 
Date: Thu, 06 Aug 2009 03:40:59 GMT 
X-AspNet-Version: 2.0.50727 
Set-Cookie: My.Common.TestCookieInfo=Pkid=999&TestValue=aaabbbcccdddeee; expires=Fri, 07-Aug-2009 03:40:59 GMT; path=/ 
Cache-Control: private 
Content-Type: text/html; charset=utf-8 
Content-Length: 558 
Connection: Close 

4.Cookies如何查看

(1)查看Cookies的txt文件

IE用戶能夠直接查看Cookies的txt文件。 
好比:C:\Documents and Settings\Administrator\Cookies\administrator@localhost[1].txt

 

(2)使用插件

FF下使用Web Developer插件能夠很方便的查看、刪除和修改Cookies:

插件截圖:

image 

查看頁面Cookies:

image

 

 

 

三. Cookies高級知識

1.Cookie 的限制

大多數瀏覽器支持最大爲 4096 字節的 Cookie。

瀏覽器還限制站點能夠在用戶計算機上存儲的 Cookie 的數量。大多數瀏覽器只容許每一個站點存儲 20 個 Cookie;注意這裏的20個是指主鍵值,也就是20條Cookies記錄,可是每一個Cookies記錄還能夠包含若干子鍵,下面會詳細解釋。若是試圖存儲更多 Cookie,則最舊的 Cookie 便會被丟棄。有些瀏覽器還會對它們將接受的來自全部站點的 Cookie 總數做出絕對限制,一般爲 300 個。

2.Cookies的存儲格式

Cookies能夠包含一個主鍵, 主鍵再包含子鍵。好比asp.net中獲取Cookies的格式是:

Request.Cookies[key][subkey].ToString();

 

其中的key就是主鍵,subkey就是主鍵關聯的子鍵。

(1)本地磁盤存儲格式:

My.Common.TestCookieInfo
Pkid=999&TestValue=aaabbbcccdddeee
localhost/
1536
3059603968
30021392
2348960464
30021191
*

其中的Pkid=999&TestValue=aaabbbcccdddeee 是Cookies的值,因爲使用了subkey=subvalue的格式, 因此此Cookies是包含子鍵的。

(2)Javascript中的Cookie格式

在Javascript中給的Cookie是一個字符串,經過document.cookies獲取。字符格式以下:

My.Common.SubKey=Pkid=999&TestValue=aaabbbcccdddeee; SingleKey=SingleKeyValue

 

上面的字符串包含了兩個Cookies,一個是不包含子鍵的SingleKey, 一個是包含pkid和TextValue兩個子鍵的My.Common.SubKey,兩個Cookie經過「;」分割。

(3)Asp.Net中的Cookies格式

和全部的服務器端語言同樣,Asp.Net中使用集合類保存Cookies集合:

public sealed class HttpCookieCollection : NameObjectCollectionBase {...}


經過HttpResquest和HttpResponse對象的Cookies屬性,能夠獲取和寫入當前頁面的Cookies。

 

3.Cookies的內容編碼格式

Cookies的值中能夠保存除了「;」之外的標點符號。可是不能保存漢字。保存漢字會出現亂碼。

因此對於Cookies中的內容要進行統一的編碼和解碼。爲了在瀏覽器端和服務器端都可以進行解碼和編碼, 因此要統一使用UTF編碼格式。

主要是由於javascript中只能使用UTF編碼格式。

 

4.Cookies的Path屬性

Cookies的Path屬性表示當前的Cookies能夠做用在網站的那個路徑下。

好比下面的兩個同名的Cookies:

image

容許存在兩個同名可是Path不一樣的Cookies。

不管是服務器端仍是客戶端,在獲取時優先獲取本頁路徑下面的Cookies。

也就是說若是在、/chapter10/路徑下面的頁面, 獲取testKey這個Cookies的值,則只能獲取到testValue222222這個值。

 

5.Cookies的過時時間

若是保存Cookies時未設置過時時間, 則Cookies的過時時間爲「當前瀏覽器進程有效」,即和Session同樣關閉瀏覽器後則消失。在asp.net中還能夠經過設置HttpCookie對象的過時時間爲DateTime.MinValue來指定此Cookies爲跟隨瀏覽器生效。(這句話來之不易啊,在腦殼等人的幫助下才查到的。)

若是設置了過時時間而且大於當前時間,則會保存Cookies值。

若是設置了過時時間可是小於等於當前時間,則清除Cookies值。

 

6.Cookies與Session

有時咱們會忽略Cookies與Session的關係。可是二者是密不可分的。

Session的惟一標示:SessionID是一般保存在Cookies中的(也能夠保存在URL中)。對於Asp.Net而言,SessionID保存在鍵值爲「ASP.NET_SessionId」的Cookies中,如圖:

image

由於Cookies的存儲數量是有限制的,因此咱們的系統在保存Cookies的時候必定要注意防止沖掉這一個關鍵的Cookies。在下文介紹的最佳實踐-以強對象方式保存Cookies的代碼中特地對這個Cookies作了處理。

注意,在客戶端使用javascript腳本沒法獲取「ASP.NET_SessionId」的Cookies, 由於此Cookies在服務器端設置了HttpOnly屬性爲true。

ASP.Net中HttpCookie對象的HttpOnly 屬性 指定一個Cookie 是否可經過客戶端腳本訪問。不能經過客戶端腳本訪問爲 true;不然爲 false。默認值爲 false。此屬性並不能徹底阻止客戶端在本地獲取cookies,可是能夠增長經過腳本直接獲取的難度。

Microsoft Internet Explorer 版本 6 Service Pack 1 和更高版本支持 Cookie 屬性 HttpOnly

 

7.Cookies加密

在設置Cookies的屬性時,有一個選項Secure用來控制Cookie的加密特性。

若是經過 SSL 鏈接 (HTTPS) 傳輸 Cookie,則爲 true;不然爲 false。默認爲 false。

若是咱們保存一個Cookies並設置加密,那麼在非HTTPS的頁面中,不管是使用javascript仍是服務器端都沒法得到此Cookies。可是在本地依然能夠看到此Cookies的存在。

 

8.Cookies與Ajax

若是Ajax請求訪問一個服務器頁面,此服務器頁面是能夠向用戶瀏覽器寫入Cookies和Session的。

 

四. Cookies最佳實踐

在瞭解了Cookies的相關知識後,下面提出最佳的事件方法。其中包括客戶端和服務器端兩部分。

(1)Asp.Net 中保存Cookies

一般,咱們使用Request和Response對象來直接操做Cookies:

寫入Cookies:

Response.Cookies["k1"].Value = "k1Value"; Response.Cookies["k2"]["k2-1"] = "k2-1Value"; Response.Cookies.Add(new HttpCookie("k3", "k3Value"));

 

讀取Cookies:

Request["k1"] ;
Request.Cookies["k1"].Value ;
Request.Cookies["k2"]["k2-1"]; Request.Cookies.Get(0).Value;

 

注意Request["k1"]這個你們熟悉的獲取get和post參數的方法,同時還可以獲取Cookies的值!

另外上面語句中的有些是必須經過Value屬性訪問的,有些則不須要。

(2)以對象方式保存Cookies

下面提供一個能夠以對象方式總體保存Cookies的工具類。而且只佔用一條Cookies,全部的屬性都存在子鍵上。

  • 源代碼:  
    /// <summary>
    /// Cookies基類。將須要保存Cookies的數據類此類派生,能夠將強類型對象在Cookies中的保存和讀取。 /// </summary> /// <remarks> /// 2009.8.6 ziqiu.zhang created /// </remarks> /// <example> /// 假設MyCookiesInfo是從 從Cookies中獲取對象: /// <code> /// CookieInfo item = new CookieInfo(); //new之後已經從Cookies中構造了對象。 /// </code> /// 將對象保存在Cookies中: /// <code> /// CookieInfo item = new CookieInfo(); /// item.value = "test value"; /// item.SetCookies("1"); //Cookies有效期爲1天 /// </code> /// </example> [System.Serializable] public class CookieInfo { #region ==================== Constructed Method ==================== /// <summary> /// 構造函數 /// </summary> public CookieInfo() { } #endregion #region ==================== Public Method ==================== /// <summary> /// 獲得當前Cookies的過時時間 /// </summary> /// <returns>過時時間</returns> public DateTime GetExpiresTime() { string cookieName = GetType().ToString(); if (HttpContext.Current.Request.Cookies[cookieName] != null) { return HttpContext.Current.Request.Cookies[cookieName].Expires; } return DateTime.MinValue; } /// <summary> /// 保存Cookies,過時時間爲瀏覽器關閉則失效。 /// </summary> /// <param name="expiresTime">Cookies過時事件</param> /// <returns>是否保存成功</returns> public bool Save() { return this.Save(DateTime.MinValue); } /// <summary> /// 保存Cookies,須要指定過時時間。 /// </summary> /// <param name="expiresTime">Cookies過時事件</param> /// <returns>是否保存成功</returns> public bool Save(DateTime expiresTime) { string CookieName = GetType().ToString(); HttpCookie SessionCookie = null; //對 SessionId 進行備份. if (HttpContext.Current.Request.Cookies["ASP.NET_SessionId"] != null) { string SesssionId = HttpContext.Current.Request.Cookies["ASP.NET_SessionId"].Value.ToString(); SessionCookie = new HttpCookie("ASP.NET_SessionId"); SessionCookie.Value = SesssionId; } //設定cookie 過時時間. DateTime dtExpiry = expiresTime; HttpContext.Current.Response.Cookies[CookieName].Expires = dtExpiry; //設定cookie 域名. string domain = string.Empty; if (HttpContext.Current.Request.Params["HTTP_HOST"] != null) { //domain = "www.elong.com"; domain = HttpContext.Current.Request.Params["HTTP_HOST"].ToString(); } //若是是www.elong.com或多級域名,須要轉化爲elong.com if (domain.IndexOf(".") > -1) { string[] temp = domain.Split('.'); if (temp.Length >= 3) { domain = temp[temp.Length - 2].Trim() + "." + temp[temp.Length - 1].Trim(); } HttpContext.Current.Response.Cookies[CookieName].Domain = domain; } //把類的屬性, 寫入Cookie. PropertyInfo[] Propertys = GetType().GetProperties(); foreach (PropertyInfo pi in Propertys) { object oj = pi.GetValue(this, null); Type type = pi.PropertyType; string valueStr = string.Empty; if (oj != null && oj.ToString() != string.Empty) { if (type == Type.GetType("System.DateTime")) { valueStr = ((DateTime)oj).ToString("yyyy/MM/dd HH:mm:ss", System.Globalization.DateTimeFormatInfo.InvariantInfo); } else { valueStr = oj.ToString(); } HttpContext.Current.Response.Cookies[CookieName][pi.Name] = HttpUtility.UrlEncode(valueStr); } } //若是cookie總數超過20 個, 重寫ASP.NET_SessionId, 以防Session 丟失. if (HttpContext.Current.Request.Cookies.Count > 20 && SessionCookie != null) { if (SessionCookie.Value != string.Empty) { HttpContext.Current.Response.Cookies.Remove("ASP.NET_SessionId"); HttpContext.Current.Response.Cookies.Add(SessionCookie); } } return true; } /// <summary> /// 找回Cookie值 /// </summary> public void Load() { string cookieValue = string.Empty; string CookieName = GetType().ToString(); //經過遍歷屬性, 從cookie 中找回值, 回寫到屬性. PropertyInfo[] Propertys = GetType().GetProperties(); foreach (PropertyInfo pi in Propertys) { try { cookieValue = HttpUtility.UrlDecode(HttpContext.Current.Request.Cookies[CookieName][pi.Name].ToString()); } catch { cookieValue = string.Empty; } if (pi.CanWrite && cookieValue != null && cookieValue != string.Empty) { try { object obb = cookieValue; Type type = pi.PropertyType; obb = Convert.ChangeType(obb, type); pi.SetValue(this, obb, null); } catch { } } } } #endregion }
  • 使用

首先說明如何使用此類。

爲想要保存在Cookies中的類創建模型,而且繼承自CookieInfo便可。好比下面創建了MyCookieInfo類,其中包含屬性pkid,TestValue和TestDateTime:

    /// <summary>
    /// 保存Cookies的數據對象 /// </summary> [System.Serializable] public class MyCookieInfo : CookieInfo { private int m_Pkid = 0; public int Pkid { get { return m_Pkid ; } set { m_Pkid = value ; } } private string m_TestValue = ""; public string TestValue { get { return m_TestValue; } set { m_TestValue = value; } } private DateTime m_TestDateTime = DateTime.Now; public DateTime TestDateTime { get { return m_TestDateTime; } set { m_TestDateTime = value; } } }

 

接下來就可使用對象的Save和Load方法保存和讀取Cookies:

  • 保存 
    Save方法有兩個重載,不帶參數的Save方法表示Cookies的過時時間與瀏覽器相同,即瀏覽器關閉則Cookies消失。不然須要傳入Cookies過時時間。
    MyCookieInfo testCookies = new MyCookieInfo();
    testCookies.Pkid = 1;
    testCookies.TestValue = "中文測試";
    testCookies.Save(); 
  • 讀取 
    MyCookieInfo testCookies = new MyCookieInfo(); testCookies.Load();
    this.lblMsg.Text = "Pkid:" + testCookies.Pkid.ToString(); this.lblMsg.Text += ",TestValue:" + testCookies.TestValue.ToString(); this.lblMsg.Text += ",TestDateTime:" + 
    testCookies.TestDateTime.ToString("yyyy/MM/dd HH:mm:ss",
    System.Globalization.DateTimeFormatInfo.InvariantInfo);

如今咱們已經能夠將一個強類型的對象讀取和保存Cookies了。

 

 

(3)使用Javascript操做Cookies

在客戶端咱們一樣須要操做Cookies。

下面是封裝了的專門用於操做Cookies的jQuery工具函數。若是還有人不知道jQuery是什麼,請參考個人「從零開始學習jQuery」系列教程:

http://www.cnblogs.com/zhangziqiu/archive/2009/04/30/jQuery-Learn-1.html

固然此工具函數稍加修改,就能夠變成標準的Javascript函數。

下載地址:http://files.cnblogs.com/zhangziqiu/jquery.extend-lastest.js

工具函數說明:

方法簽名: jQuery.cookie(name, subName, value,  options)

方法說明:讀取、寫入、刪除Cookies

方法參數:

名稱 說明 舉例
name cookies的主鍵值 讀取主鍵: 
$.cookie("singleKey")


寫入cookies,值爲字符串: 
$.cookie("singleKey", "", "singleKey-value", { expires: 1, path: "/", secure: false })
subName 子鍵名稱。在寫入時請傳遞空或者null 讀取子鍵: 
$.cookie("multiKey", "subName1")


寫入cookies,值爲對象: 
var subNameObj = { subName1: "aaa", subName2: "bbb", subName3: "ccc" };
$.cookie("multiKey", "", subNameObj, { expires: 1, path: "/", secure: false });
value Cookies值,能夠是字符串或者對象。 
若是是對象,則將對象的每一個屬性保存在Cookies子鍵。
參見上面實例。
options 參數: 
expires:能夠是數字或者Data類型的對象。 
若是傳入數字表示幾天後過時。
path:路徑,默認爲域名根目錄(「/」)。 
secure:是否啓用加密,默認爲否。 



指定過時時間:

var myDate = new Date(); myDate.setFullYear(2009, 10, 10); $.cookie("singleKey", "", "singleKey-value", { expires: myDate, secure: false })
 

1天后過時:

var time = Date();
$.cookie("singleKey", "", "singleKey-value", { expires: 1, path: "/", secure: false })

 

五.總結

好久沒有發表文章了,做爲博客園改版後個人第一篇文章, 但願對你們的工做能有所幫助。 歡迎拍磚!

相關文章
相關標籤/搜索