一前言
Cookies想必所有人都了解 但是未必所有人都精通本文講解了Cookies的各方面知識 並且提出來了最佳實踐這是筆者在日常工作中的積累和沉澱
二基礎知識
什麼是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 來記錄用戶已經登錄這樣用戶就不必每次都輸入憑據
Cookies如何存儲
Cookies保存在用戶的本地機器上不同的浏覽器存儲在不同的文件夾中並且按照域名分別保存即網站之間的Cookies不會彼此覆蓋
IE浏覽器的用戶可以通過在本地的文檔中找到Cookies的txt文件 不同操作系統的位置不同windows server /xp都保存在
C:\Documents and Settings\Administrator\Cookies 文件夾下
其中名稱txt按照域名保存比如localhost域下的cookies為
administrator@localhost[]txt 或者 administrator@localhost[]txt
其中後面的[]和[]是隨著每次保存交替變化的
Cookies如何傳遞
Cookies的信息是在Web服務器和浏覽器之間傳遞的保存在Http請求中
()請求頁面
在請求一個頁面的Http頭中會將屬於此頁面的本地Cookies信息加在Http頭中注意下面加粗的部分
GET /Cookies/Testaspx HTTP/ Host: localhost: UserAgent: Mozilla/ (Windows; U; Windows NT ; zhCN; rv:) Gecko/ Firefox/ GTB (NET CLR ) Accept: text/htmlapplication/xhtml+xmlapplication/xml;q=*/*;q= AcceptLanguage: zhcnzh;q= AcceptEncoding: gzipdeflate AcceptCharset: GButf;q=*;q= KeepAlive: Connection: keepalive Cookie: MyCommonTestCookieInfo=Pkid=&TestValue=aaabbbcccdddeee
()頁面響應
如果頁面要求寫入Cookies信息則返回的Http如下注意加粗的部分
HTTP/x OK Server: ASPNET Development Server/ Date: Thu Aug :: GMT XAspNetVersion: SetCookie: MyCommonTestCookieInfo=Pkid=&TestValue=aaabbbcccdddeee; expires=Fri Aug :: GMT; path=/ CacheControl: private ContentType: text/html; charset=utf ContentLength: Connection: Close
Cookies如何查看
()查看Cookies的txt文件
IE用戶可以直接查看Cookies的txt文件
比如C:\Documents and Settings\Administrator\Cookies\administrator@localhost[]txt
()使用插件
FF下使用Web Developer插件可以很方便的查看刪除和修改Cookies
查看頁面Cookies
三 Cookies高級知識
Cookie 的限制
大多數浏覽器支持最大為 字節的 Cookie
浏覽器還限制站點可以在用戶計算機上存儲的 Cookie 的數量大多數浏覽器只允許每個站點存儲 個 Cookie注意這裡的個是指主鍵值也就是條Cookies記錄但是每個Cookies記錄還可以包含若干子鍵下面會詳細解釋如果試圖存儲更多 Cookie則最舊的 Cookie 便會被丟棄有些浏覽器還會對它們將接受的來自所有站點的 Cookie 總數作出絕對限制通常為 個
Cookies的存儲格式
Cookies可以包含一個主鍵 主鍵再包含子鍵比如中獲取Cookies的格式是
RequestCookies[key][subkey]ToString();
其中的key就是主鍵subkey就是主鍵關聯的子鍵
()本地磁盤存儲格式
MyCommonTestCookieInfoPkid=&TestValue=aaabbbcccdddeeelocalhost/*
其中的Pkid=&TestValue=aaabbbcccdddeee 是Cookies的值由於使用了subkey=subvalue的格式 所以此Cookies是包含子鍵的
()Javascript中的Cookie格式
在Javascript中給的Cookie是一個字符串通過okies獲取字符格式如下
MyCommonSubKey=Pkid=&TestValue=aaabbbcccdddeee; SingleKey=SingleKeyValue
上面的字符串包含了兩個Cookies一個是不包含子鍵的SingleKey 一個是包含pkid和TextValue兩個子鍵的MyCommonSubKey兩個Cookie通過;分割
()AspNet中的Cookies格式
和所有的服務器端語言一樣AspNet中使用集合類保存Cookies集合
public sealed class HttpCookieCollection : NameObjectCollectionBase{}
通過HttpResquest和HttpResponse對象的Cookies屬性可以獲取和寫入當前頁面的Cookies
Cookies的內容編碼格式
Cookies的值中可以保存除了;以外的標點符號但是不能保存漢字保存漢字會出現亂碼
所以對於Cookies中的內容要進行統一的編碼和解碼為了在浏覽器端和服務器端都能夠進行解碼和編碼 所以要統一使用UTF編碼格式
主要是因為javascript中只能使用UTF編碼格式
Cookies的Path屬性
Cookies的Path屬性表示當前的Cookies可以作用在網站的那個路徑下
比如下面的兩個同名的Cookies
允許存在兩個同名但是Path不同的Cookies
無論是服務器端還是客戶端在獲取時優先獲取本頁路徑下面的Cookies
也就是說如果在/chapter/路徑下面的頁面 獲取testKey這個Cookies的值則只能獲取到testValue這個值
Cookies的過期時間
如果保存Cookies時未設置過期時間 則Cookies的過期時間為當前浏覽器進程有效即和Session一樣關閉浏覽器後則消失在中還可以通過設置HttpCookie對象的過期時間為DateTimeMinValue來指定此Cookies為跟隨浏覽器生效(這句話來之不易啊在腦袋等人的幫助下才查到的)
如果設置了過期時間並且大於當前時間則會保存Cookies值
如果設置了過期時間但是小於等於當前時間則清除Cookies值
Cookies與Session
有時我們會忽略Cookies與Session的關系但是兩者是密不可分的
Session的唯一標示SessionID是通常保存在Cookies中的(也可以保存在URL中)對於AspNet而言SessionID保存在鍵值為ASPNET_SessionId的Cookies中如圖
因為Cookies的存儲數量是有限制的所以我們的系統在保存Cookies的時候一定要注意防止沖掉這一個關鍵的Cookies在下文介紹的最佳實踐以強對象方式保存Cookies的代碼中特意對這個Cookies做了處理
注意在客戶端使用javascript腳本無法獲取ASPNET_SessionId的Cookies 因為此Cookies在服務器端設置了HttpOnly屬性為true
ASPNet中HttpCookie對象的HttpOnly 屬性 指定一個Cookie 是否可通過客戶端腳本訪問不能通過客戶端腳本訪問為 true否則為 false默認值為 false此屬性並不能完全阻止客戶端在本地獲取cookies但是可以增加通過腳本直接獲取的難度
Microsoft Internet Explorer 版本 Service Pack 和更高版本支持 Cookie 屬性 HttpOnly
Cookies加密
在設置Cookies的屬性時有一個選項Secure用來控制Cookie的加密特性
如果通過 SSL 連接 (HTTPS) 傳輸 Cookie則為 true否則為 false默認為 false
如果我們保存一個Cookies並設置加密那麼在非HTTPS的頁面中無論是使用javascript還是服務器端都無法獲得此Cookies但是在本地依然可以看到此Cookies的存在
Cookies與Ajax
如果Ajax請求訪問一個服務器頁面此服務器頁面是可以向用戶浏覽器寫入Cookies和Session的
四 Cookies最佳實踐
在了解了Cookies的相關知識後下面提出最佳的事件方法其中包括客戶端和服務器端兩部分
()AspNet 中保存Cookies
通常我們使用Request和Response對象來直接操作Cookies
寫入Cookies
ResponseCookies[k]Value = kValue;ResponseCookies[k][k] = kValue;ResponseCookiesAdd(new HttpCookie(k kValue));
讀取Cookies
Request[k] ;RequestCookies[k]Value ;RequestCookies[k][k];RequestCookiesGet()Value;
注意Request[k]這個大家熟悉的獲取get和post參數的方法同時還能夠獲取Cookies的值!
另外上面語句中的有些是必須通過Value屬性訪問的有些則不需要
()以對象方式保存Cookies
下面提供一個可以以對象方式整體保存Cookies的工具類並且只占用一條Cookies所有的屬性都存在子鍵上
源代碼
/// /// Cookies基類將需要保存Cookies的數據類此類派生可以將強類型對象在Cookies中的保存和讀取
/// /// /// ziqiuzhang created /// /// /// 假設MyCookiesInfo是從 從Cookies中獲取對象
/// /// CookieInfo item = new CookieInfo(); //new以後已經從Cookies中構造了對象
/// /// 將對象保存在Cookies中 /// /// CookieInfo item = new CookieInfo();
/// itemvalue = test value; /// itemSetCookies(); //Cookies有效期為天
/// /// [SystemSerializable] public class CookieInfo {
#region ==================== Constructed Method ====================
/// /// 構造函數 /// public CookieInfo()
{ }
#endregion #region ==================== Public Method ====================
/// /// 得到當前Cookies的過期時間
/// /// 過期時間 public DateTime GetExpiresTime()
{
string cookieName = GetType()ToString();
if (HttpContextCurrentRequestCookies[cookieName] != null)
{
return HttpContextCurrentRequestCookies[cookieName]Expires;
}
return DateTimeMinValue;
} /// /// 保存Cookies過期時間為浏覽器關閉則失效
/// /// Cookies過期事件 /// 是否保存成功 public bool Save() { return thisSave(DateTimeMinValue); }
/// /// 保存Cookies需要指定過期時間 /// /// Cookies過期事件
/// 是否保存成功 public bool Save(DateTime expiresTime)
{
string CookieName = GetType()ToString(); HttpCookie SessionCookie = null;
//對 SessionId 進行備份
if (HttpContextCurrentRequestCookies[ASPNET_SessionId] != null)
{
string SesssionId = HttpContextCurrentRequestCookies[ASPNET_SessionId]ValueToString();
SessionCookie = new HttpCookie(ASPNET_SessionId); SessionCookieValue = SesssionId;
} //設定cookie 過期時間 DateTime dtExpiry = expiresTime;
HttpContextCurrentResponseCookies[CookieName]Expires = dtExpiry;
//設定cookie 域名 string domain = stringEmpty; if (HttpContextCurrentRequestParams[HTTP_HOST] != null)
{
//domain = ; domain = HttpContextCurrentRequestParams[HTTP_HOST]ToString();
} //如果是或多級域名需要轉化為 if (domainIndexOf() > )
{
string[] temp = domainSplit(); if (tempLength >= )
{ domain = temp[tempLength ]Trim() + + temp[tempLength ]Trim();
} HttpContextCurrentResponseCookies[CookieName]Domain = domain; }
//把類的屬性 寫入Cookie PropertyInfo[] Propertys = GetType()GetProperties(); foreach (PropertyInfo pi in Propertys)
{
object oj = piGetValue(this null); Type type = piPropertyType;
string valueStr = stringEmpty; if (oj != null && ojToString() != stringEmpty)
{ if (type == TypeGetType(SystemDateTime))
{
valueStr = ((DateTime)oj)ToString(yyyy/MM/dd HH:mm:ss SystemGlobalizationDateTimeFormatInfoInvariantInfo);
}
else
{
valueStr = ojToString();
} HttpContextCurrentResponseCookies[CookieName][piName] = HttpUtilityUrlEncode(valueStr);
}
}
//如果cookie總數超過 個 重寫ASPNET_SessionId 以防Session 丟失
if (HttpContextCurrentRequestCookiesCount > && SessionCookie != null)
{
if (SessionCookieValue != stringEmpty)
{
HttpContextCurrentResponseCookiesRemove(ASPNET_SessionId); HttpContextCurrentResponseCookiesAdd(SessionCookie);
}
}
return true;
} /// /// 找回Cookie值 /// public void Load() { string cookieValue = stringEmpty;
string CookieName = GetType()ToString();
//通過遍歷屬性 從cookie 中找回值 回寫到屬性 PropertyInfo[] Propertys = GetType()GetProperties(); foreach (PropertyInfo pi in Propertys)
{
try
{ cookieValue = HttpUtilityUrlDecode(HttpContextCurrentRequestCookies[CookieName][piName]ToString());
}
catch
{ cookieValue = stringEmpty;
}
if (piCanWrite && cookieValue != null && cookieValue != stringEmpty) { try
{
object obb = cookieValue; Type type = piPropertyType; obb = ConvertChangeType(obb type); piSetValue(this obb null);
}
catch
{ } } }
}
#endregion
}
使用
首先說明如何使用此類
為想要保存在Cookies中的類建立模型並且繼承自CookieInfo即可比如下面建立了MyCookieInfo類其中包含屬性pkidTestValue和TestDateTime
/// /// 保存Cookies的數據對象 /// [SystemSerializable] public class MyCookieInfo : CookieInfo
{ private int m_Pkid = ; 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 = DateTimeNow; public DateTime TestDateTime
{ get
{ return m_TestDateTime;
}
set
{
m_TestDateTime = value;
}
}
}
接下來就可以使用對象的Save和Load方法保存和讀取Cookies
保存
Save方法有兩個重載不帶參數的Save方法表示Cookies的過期時間與浏覽器相同即浏覽器關閉則Cookies消失否則需要傳入Cookies過期時間
MyCookieInfo testCookies = new MyCookieInfo(); testCookiesPkid = ; testCookiesTestValue = 中文測試; testCookiesSave();
讀取
MyCookieInfo testCookies = new MyCookieInfo();testCookiesLoad();thislblMsgText = Pkid: + testCookiesPkidToString();thislblMsgText += TestValue: + testCookiesTestValueToString();thislblMsgText += TestDateTime: + testCookiesTestDateTimeToString(yyyy/MM/dd HH:mm:ss SystemGlobalizationDateTimeFormatInfoInvariantInfo);現在我們已經可以將一個強類型的對象讀取和保存Cookies了
()使用Javascript操作Cookies
在客戶端我們同樣需要操作Cookies
下面是封裝了的專門用於操作Cookies的jQuery工具函數如果還有人不知道jQuery是什麼請參考我的從零開始學習jQuery系列教程
l
當然此工具函數稍加修改就可以變成標准的Javascript函數
下載地址lastestjs
工具函數說明
方法簽名 okie(name subName value options)
方法說明讀取寫入刪除Cookies
方法參數
名稱 說明 舉例
name cookies的主鍵值 讀取主鍵
okie(singleKey)
寫入cookies值為字符串
okie(singleKey singleKeyvalue { expires: path: / secure: false })
subName 子鍵名稱在寫入時請傳遞空或者null 讀取子鍵
okie(multiKey subName)
寫入cookies值為對象
var subNameObj = { subName: aaa subName: bbb subName: ccc };okie(multiKey subNameObj { expires: path: / secure: false });
value Cookies值可以是字符串或者對象
如果是對象則將對象的每個屬性保存在Cookies子鍵 參見上面實例
options 參數
expires可以是數字或者Data類型的對象
如果傳入數字表示幾天後過期
path路徑默認為域名根目錄(/)
secure是否啟用加密默認為否
指定過期時間
var myDate = new Date();myDatesetFullYear( );okie(singleKey singleKeyvalue { expires: myDate secure: false }) 天後過期
var time = Date();okie(singleKey singleKeyvalue { expires: path: / secure: false })
五總結
很久沒有發表文章了作為博客園改版後我的第一篇文章 希望對大家的工作能有所幫助 歡迎拍磚!
From:http://tw.wingwit.com/Article/program/net/201311/13358.html