Cookie這個東東,第一次接觸WEB的時候,就了解它了,用起來嘛也很簡單.但是對這個東西一直缺少完整的認識,最近正好有時間,看了些資料,結合自己以前寫的代碼,在這裡做個簡單的完整介紹吧.
基本概念
Cookie是Web服務器向用戶浏覽器發送的一段Ascii文本.一旦接受到cookie,浏覽器會把cookie的信息片段以"鍵/值"對的形式保存在本地.這以後,每次想同一服務器發送請求的時候,Web浏覽器都會發送站點以前存儲在本地的cookie.浏覽器和Web服務器的通訊是通過Http協議進行通訊的,而cookie就保存在Http協議的請求部分(Set-Cookie).
具體形式如下:
Set-Cookie:customer=huangxp; path=/foo; domain=ibm.com; expires= Wednesday, 19-OCT-05 23:12:40 GMT; [secure];HttpOnly
其中每個屬性的解釋:
domain: 關聯的域名,例如http://ibm.com/foo/index.aspx, 它的domain = ibm.com,該domain默認為當前請求的域,但是如果cookie中domain的值和請求的域不相符的話,這個cookie就會被忽略.
path: 控制哪些訪問能觸發發送.例如請求的地址是上面的URL,如果path=/foo,這個cookie就會被發送,但是path為其他的話,該cookie會被忽略.
expires: cookie的過期時間
secure: 如果secure 這個詞被作為Set-Cookie 頭的一部分,那麼cookie 只能通過安全通道傳輸(目前即SSL通道)。否則,浏覽器將忽略此Cookie
HttpOnly:只是該cookie是否能被客戶端訪問,不過該數據要依賴與浏覽器是否支持,一般IE6以上的版本都支持該屬性.
"鍵/值"對: customer=huangxp或customer=a1=huangxp&a2=huangxp
介紹完Cookie的基本原理後,下面簡單描述下一次典型的網絡浏覽過程
浏覽器對於Web服務器應答包頭中Cookie的操作步驟:
1.從Web服務器的應答包頭中提取所有的cookie。
2.解析這些cookie的組成部分(名稱,值,路徑等等)。
3.判定主機是否允許設置這些cookie。允許的話,則把這些Cookie存儲在本地。
浏覽器對Web服務器請求包頭中所有的Cookie進行篩選的步驟:
1.根據請求的URL和本地存儲cookie的屬性,判斷那些Cookie能被發送給Web服務器。
2.對於多個cookie,判定發送的順序。
3.把需要發送的Cookie加入到請求HTTP包頭中一起發送。
客戶端和服務器端對Cookie的操作
它們之間的交互我想通過下面的DEMO可以更好的讓大家了解
a, 服務器端輸出Cookie,客戶端獲取Cookie
Code
protected void Page_Load(object sender, EventArgs e)
{
HttpCookie ck = new HttpCookie("TestCK");
ck.Values.Add("Name1", "1");
ck.Values.Add("Name2", "2");
HttpCookie ck1 = new HttpCookie("TestCK_2");
ck1.Value = "1";
this.Response.Cookies.Add(ck);
this.Response.Cookies.Add(ck1);
}
Code
function GetCookie(){
document.write(document.cookie);
}
服務器端輸出TestCk,TestCK_2這兩個Cookie,那麼客戶段獲取的Cookie是"TestCK=Name1=1&Name2=2; TestCK_2=1"
有些需要注意的地方:
1,客戶端的document.cookie只能獲取獲取HttpCookie的Name,Value和Values屬性.
2,如果HttpCookie中的Values有值的話,那麼在客戶端輸出的是name1=1&name2=2&......這種形式,如果Value有值,輸出的為1,如果Value和Values都有值,輸出的是1&name1=1&name2=2&...這種形式
3,多個Cookie在客戶端document.cookie中是通過";"來隔離的
b, 客戶端輸出Cookie,服務器端獲取
Code
function SetCookie(){
document.cookie = "TestCK=Name1=1&Name2=2";
var d1 = new Date(2008, 9, 17);
document.cookie = "TestCK_2=1;expires=" + d1;
}
執行完上面方法後,在客戶端獲取的Cookie如下圖
服務器端獲取的Cookie:
需要注意的地方:
1, 設置多個Cookie的時候必須按照上面的設置,不能"TestCK=Name1=1&Name2=2; TestCK_2=1"這樣賦值
2, 如果要刪除Cookie,可以設置expires屬性為過期的時間,例如"document.cookie = TestCK_2=1;expires = 過期時間"
3, 對於在客戶端設置的expires..這些屬性,在服務器端獲取不到,只能獲取Value和Values屬性(至於為什麼會這樣我也沒有弄明白?)
不管在服務器端和客戶端都要注意對domain,path,httponly....這些的設置,在沒有特殊需求的時候,別去設置他們,否則可能會造成Cookie遺失.
自定義Cookie類(客戶端操作Cookie)
根據document.cookie對Cookie的支持,在賦值和獲取值的操作上還是有點麻煩,不像服務器端的HttpCookie那樣方便,則下面提供了個自己寫的在客戶端操作Cookie的對象.基本和HttpCookie相對應,目的是為了操作起來更加方便一些.
CookieObj類: 對應與HttpCookie的Name和Values, __CookieValue為私有屬性,一般不要使用,它的值為當前Name對應的document.cookie.
Set方法: 為當前Cookie賦值,設置Values屬性.
Remove方法: 根據Key刪除Values中的元素.
Get方法: 獲取默認的值,因為document.cookie的值可能為"1&name1=1&name2=2"這種形式,所以它獲取的是1的元素
GetItemByKey方法: 根據Key獲取元素
KeyValuePair類: 這個只是一個鍵/值對的類.
CookieAdapter類: 提供一種document.cookie和CookieObj之間的轉換
CookieAdapter.GetCookies方法 : 獲取所有的Cookie,並且轉換為CookieObj的數組集合.
CookieAdapter.GetCookieByName方法: 根據Cookie的名稱,來獲取對應的Cookie.
CookieAdapter.SetCookies方法: 設置document.cookie,接受的參數是由CookieObj對象組成的數組集合.
Code
/**//* Cookie類 */
function CookieObj(name){
/**//* (Public)名稱 */
this.Name = name;
/**//* (Public)Cookie的鍵/值對 */
this.KeyValues = new Array();
/**//* (Private)document.cookie的字符串 */
this.__CookieValue;
}
CookieObj.prototype = {
/**//* (Public)設置鍵/值對 */
Set : function(key, value){
switch(arguments.length){
case 0:
return;
break;
case 1:
if(!key){
return;
}
var item = this.GetItemByKey("__Default");
if(!item){
item = new KeyValuePair("__Default", key);
this.KeyValues.push(item);
}
else{
item.Value = key;
}
break;
case 2:
// key或value為空
if(!key || !value){
return;
}
var item = this.GetItemByKey(key);
//item為空的時候
if(!item){
item = new KeyValuePair(key, value);
this.KeyValues.push(item);
}
else{
item.Value = value;
}
break;
}
},
/**//* (Public)刪除鍵 */
Remove : function(key){
//key為空
if(!key){
return;
}
var index = this._GetIndexByKey(key);
//存在數據
if(index > -1){
this.KeyValues.splice(index, 1);
}
},
/**//* (Public)獲取值 */
Get : function(){
return this.GetItemByKey("__Default");
},
/**//* (Public)鍵/值對的索引 */
GetItemByKey : function(key){
//key為空
if(!key){
return;
}
//存在數據
if(this.KeyValues && this.KeyValues.length >0){
for(var i=0; i< this.KeyValues.length; i++){
var obj = this.KeyValues[i];
//關鍵字存在
if(obj.Key == key){
return obj;
break;
}
}
}
return null;
},
/**//* (Private)獲取鍵/值對的Index */
_GetIndexByKey : function(key){
//存在數據
if(this.KeyValues && this.KeyValues.length >0){
for(var i=0; i< this.KeyValues.length; i++){
var obj = this.KeyValues[i];
//關鍵字存在
if(obj.Key == key){
return i;
break;
}
}
}
return -1;
}
}
/**//* 鍵/值對的類 */
function KeyValuePair(key, value){
this.Key = key;
this.Value = value;
}
/**//* Cookie和document.cookie之間的轉換,獲取,設置Cookie */
var CookieAdapter = {};
/**//* (Public)獲取所有的Cookie對象 */
CookieAdapter.GetCookies = function(){
//Cookie對象的集合
var arrCookieObjs = new Array();
//Cookie存在
if(document.cookie){
var arrCookie = document.cookie.split(";");
for(var i=0;i < arrCookie.length; i++){
var mCookieObj = CookieAdapter._ConvertToCookieObj(arrCookie[i]);
arrCookieObjs.push(mCookieObj);
}
}
return arrCookieObjs;
}
/**//* (Public)獲取指定名稱的Cookie對象 */
CookieAdapter.GetCookieByName = function(name){
//Cookie存在
if(document.cookie){
var arrCookie = document.cookie.split(";");
for(var i=0;i < arrCookie.length; i++){
var arr = arrCookie[i].split("=");
if(arr[0] == name){
var mCookieObj = CookieAdapter._ConvertToCookieObj(arrCookie[i]);
return mCookieObj;
break;
}
}
}
return null;
}
/**//* (Public)設置document.cookie */
CookieAdapter.SetCookies = function(arrCookie, expires, domain, path, secure, httponly){
//Cookie對象不為空
if(arrCookie){
for(var i = 0; i< arrCookie.length; i++){
var obj = arrCookie[i];
var str = "";
//存在鍵/值集合
if(obj.KeyValues){
for(var j =0; j< obj.KeyValues.length; j++){
var objKey = obj.KeyValues[j];
if(objKey.Key == "__Default"){
str += objKey.Value;
}
else{
str += objKey.Key + "=" + objKey.Value;
}
if(j != obj.KeyValues.length -1){
str += "&";
}
}
obj.__CookieValue = str;
}
if(str){
document.cookie = obj.Name + "=" + str;
}
else{
document.cookie = obj.Name;
}
if(expires){
document.cookie += ";expires=" + expires;
}
if(domain){
document.cookie += ";domain=" + domain;
}
if(path){
document.cookie += ";path=" + path;
}
if(secure){
document.cookie += ";" + secure;
}
if(httponly){
document.cookie += ";" + httponly;
}
}
}
}
/**//* (Private)document.cookie的轉換為Cookie對象 */
CookieAdapter._ConvertToCookieObj = function(cookieStr){
var arr = cookieStr.split("=");
//設置Cookie對象
var mCookieObj = new CookieObj(arr[0]);
if(arr.length > 1){
var strValue = cookieStr.substring(arr[0].length + 1, cookieStr.length);
mCookieObj.__CookieValue = strValue;
//存在鍵/值集合
var arrValues = strValue.split("&");
for(var j=0 ;j < arrValues.length; j++){
var arrKeyValue = arrValues[j].split("=");
if(arrKeyValue.length == 1){
mCookieObj.Set(arrKeyValue[0]);
}
else{
mCookieObj.Set(arrKeyValue[0], arrKeyValue[1]);
}
}
}
return mCookieObj;
}