一,前言
Cookies想必所有人都瞭解, 但是未必所有人都精通。本文講解了Cookies的各方面知識。
二,基礎知識
1.什麼是Cookies
Cookie 是一小段文本資訊,伴隨著使用者請求和頁面在 Web 服務器和瀏覽器之間傳遞。Cookie 包含每次使用者訪問網站時 Web 應用程式都可以讀取的資訊。
例如,如果在使用者請求網站中的頁面時應用程式發送給該使用者的不僅僅是一個頁面,還有一個包含日期和時間的 Cookie,使用者的瀏覽器在獲得頁面的同時還獲得了該 Cookie,並將它儲存在使用者硬碟上的某個檔案夾中。
以後,如果該使用者再次請求您網站中的頁面,當該使用者輸入 URL 時,瀏覽器便會在本地硬碟上尋找與該 URL 關聯的 Cookie。如果該 Cookie 存在,瀏覽器便將該 Cookie 與頁請求一起發送到您的網站。然後,應用程式便可以確定該使用者上次訪問網站的日期和時間。您可以使用這些資訊向使用者顯示一條訊息,也可以檢查到期日。
Cookie 與網站關聯,而不是與特定的頁面關聯。因此,無論使用者請求網站中的哪一個頁面,瀏覽器和伺服器都將交換 Cookie 資訊。使用者訪問不同網站時,各個網站都可能會向使用者的瀏覽器發送一個 Cookie;瀏覽器會分別儲存所有 Cookie。
Cookie 協助網站儲存有關訪問者的資訊。一般來說,Cookie 是一種保持 Web 應用程式連續性(即執行狀態管理)的方法。除短暫的實際交換資訊的時間外,瀏覽器和 Web 服務器間都是中斷連線的。對於使用者向 Web 服務器發出的每個請求,Web 服務器都會單獨處理。但是在很多情況下,Web 服務器在使用者請求頁時識別出使用者會十分有用。例如,購物網站上的 Web 服務器跟蹤每位購物者,這樣網站就可以管理購物車和其他的使用者特定資訊。因此,Cookie 可以作為一種名片,提供相關的標識資訊輔助應用程式確定如何繼續執行。
使用 Cookie 能夠達到多種目的,所有這些目的都是為了協助網站記住使用者。例如,一個實施民意測驗的網站可以簡單地將 Cookie 作為一個 Boolean 值,用它來指示使用者的瀏覽器是否已參與了投票,這樣使用者便無法進行第二次投票。要求使用者登入的網站則可以通過 Cookie 來記錄使用者已經登入,這樣使用者就不必每次都輸入憑據。
2.Cookies如何儲存
Cookies儲存在使用者的本地機器上,不同的瀏覽器儲存在不同的檔案夾中,並且按照網域名稱分別儲存。即網站之間的Cookies不會彼此覆蓋。
IE瀏覽器的使用者可以通過在本地的文檔中找到Cookies的txt檔案, 不同作業系統的位置不同,windows server 2003/xp都儲存在:
C:\Documents and Settings\Administrator\Cookies 檔案夾下。
其中名稱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:
外掛程式:
查看頁面Cookies:
三. 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:
允許存在兩個同名但是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中,
因為Cookies的儲存數量是有限制的,所以我們的系統在儲存Cookies的時候一定要注意防止衝掉這一個關鍵的Cookies。在下文介紹的最佳實務-以強對象方式儲存Cookies的代碼中特意對這個Cookies做了處理。
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工具函數。
當然此工具函數稍加修改,就可以變成標準的Javascript函數。
工具函數說明:
方法簽名: 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 }) |