- 什么是cookie?
- 承載用戶相關信息的HTTP首部
- cookie的工作原理
- cookie的缺陷
一、什么是cookie?
cookie是由服務器生成,發送給USER-Agent(一般是瀏覽器),(服務器告訴瀏覽器設置一下cookie),瀏覽器會將cookie以key/value保存到某個目錄下的文本文件內,下次請求同一個網站時就發送該cookie給服務器(前提是瀏覽器設置為啟用cookie)。cookie就是一個小型文件(瀏覽器對cookie的內存大小有限制)。
cookie可以做什么?
1.服務器可以通過cookie在客戶端緩存一些標識客戶特性的信息,比如通過個性化標識為客戶提供個性化體驗。比如推送客戶感興趣的資訊和商品。
2.服務器可以通過cookie緩存客戶的身份信息,可以讓客戶在下次訪問該網站時自動登入,提高交互體驗。
3.HTTP是無狀態的,每條請求/響應都是獨立進行的,web站點有時候需要有一種方式來區分不同用戶的HTTP事務。
二、承載用戶信息的HTTP頭部?
HTTP協議識別用戶的幾種機制:客戶端IP地址跟蹤;用戶認證識別;胖URL信息識別;cookie持久身份識別技術。這些識別技術分別對應着一些HTTP的首部信息,下表展示了承載用戶信息的HTTP首部,以及后面詳細的具體用戶識別與這些首部的關系。
首部名稱 | 首部類型 | 描述 |
From | 請求 | 用戶的E-mail地址 |
User-Agent | 請求 | 用戶的瀏覽器軟件 |
Referer | 請求 | 用戶是從這個頁面上依照連接跳轉過來的 |
Authorization | 請求 | 用戶和密碼 |
Client-IP | 擴展請求 | 客戶端的IP地址 |
X-Forwarded-For | 擴展請求 | 客戶端的IP地址 |
Cookie | 擴展請求 | 服務器產生的ID標簽 |
1.From首部包含了用戶的E-mail地址:服務器通過From首部包含的E-mail地址來識別用戶。但由於有很有不道德的服務器收集這些E-mail用來散發垃圾郵件,所以很少有瀏覽器會發送From首部。實際上From首部是由自動化的機器人(蜘蛛)發送。
2.User-Agent首部可以將用戶所用的瀏覽器的相關信息告知服務器,包括程序的名稱和版本。
3.Referer首部提供用戶來源頁面的URL。(比如從一個籃球俱樂部的網站跳到某個web服務器,這個服務器會推斷你是一個籃球迷)
4.客戶端的IP地址:HTTP首部並不承載客戶端的IP地址,但web服務器可以找到承載HTTP請求的TCP連接上的IP地址。(客戶端IP地址描述的是所用的機器,而不是用戶。如果多個用戶共享一台計算機就無法對其區分;很多因特網服務商會動態分配IP地址,因此用戶每次登入的IP可能都會不同;還有為了提高安全性,用戶都是通過網絡地址轉換防火牆來瀏覽網絡內容,這些NAT設備隱藏了防火牆后面哪些實際客戶端的IP地址,將實際的IP地址轉換成一個共享的防火牆IP地址和不同的端口號;HTTP代理通常會打開新的、到原始服務器的TCP連接,web服務器看到的將是代理服務器的IP地址,而不是客戶端的。有些代理為了繞開這個問題會添加特殊的Client-IP或X-Forwarded-For擴展首部來保存原始的IP地址,但不是所有代理都支持這種行為。)
5.用戶登入——用戶認證識別:HTTP中包含一種內建機制,可以用WWW-Authenticate首部和Authorization首部向web站點傳送用戶的相關信息。一旦登入,瀏覽器就可以不斷地在每條發往這個站點的請求中發送這個登入信息,這樣就總有登入信息可用。在后用具體的HTTP認證機制進行更加詳細的討論。(大概的過程是:當用戶通過瀏覽器訪問某個站點時,服務器不知道這個用戶的身份會返回401Login Required HTTP響應碼,並添加WWW-Authenticate首部,要求用戶登入。瀏覽器彈出登入框。只要用戶輸入用戶名和密碼,瀏覽器就會重復原來的請求。這個添加一個Authorization首部,說明用戶名和密碼,並且進行加密。今后的請求使用用戶名和密碼時,瀏覽器會自動將存儲下來的值發送出去,甚至在站點沒有要求發送時,也會經常向其發送。瀏覽器在每次請求中都向服務器發送Authorization首部作為一種身份的標識,這樣,只要登入一次,就可以在整個會話期間維持用戶的身份。)
6.胖URL:Web站點為每個用戶生成特定版本的URL來追蹤用戶身份,比如當用戶訪問某個站點時,該站點的服務器在響應報文的URL后面添加一個隨機數來標識這個用戶。這種識別用戶的方式也會存在很多問題,比如無法共享URL,不然就會將用戶積累的個人信息都共享出去;破壞緩存,為每個URL生成用戶特有的版本,就意味着不再有可供公共訪問的URL需要緩存了;逃逸口,當用戶跳轉到其他站點或者特定URL時,就很容易“逃離”胖URL會話;在繪畫間是非持久的,除非用戶收藏了胖URL,否則用戶推出登入時,所有信息都會丟失。
三、cookie的工作原理
1.cookie的屬性:不同的瀏覽器會以不同的方式來存儲cookie,網景的Navigator會將cookie存儲在一個名為cookies.txt的文本文件中。通過這個文本的數據結構來了解cookie數據的屬性。(查看cookie的方法:控制台-->Application-->cookies)
#Netscape HTTP Cookie File | ||||||
#HTTP://www.netscape.com/newsref/std/cookie_spec.html | ||||||
#This is a generated file!Do not edit. | ||||||
# | ||||||
#domain | allh | path | secure | expiration | name | value |
www.fedex.com | FALSE | / | FALSE | 1136109676 | cc | /us/ |
secure.eepulse.net | FALSE | /eePulse | FALSE | 1007162968 | cid | %FE%FF%002 |
... |
domain(域):cookie的域。
allh:是域中所有的主機獲取cookie,還是只有指定了名字的主機獲取。
path(路徑):域中與cookie相關的路徑前綴。
secure(安全):是否只有在使用SSL連接時才發送這個cookie。
expiration(過期):從格林尼治標准時間1970年1月1日00:00:00開始的cookie過期的秒數。
name(名稱):cookie變量的名稱。
value(值):cookie變量的值。
2.cookie的使用權限:只有訪問對應的站點才能攜帶對應站點的cookie信息作為HTTP首部發送給服務器,甚至對應的路徑。
3.cookie的設置:服務器在響應報文中使用Set-Cookie:"name=value"向瀏覽器中添加cookie信息。cookie的屬性也可以使用HTTP響應報文首部設置,比如可以這樣設置域(domin="baidu.com"),如果不設置就是默認為當前訪問的域。通過expiration設置cookie的生命周期,等其他cookie屬性都可以在響應報文首部設置。
4.cookie信息什么時候發送給服務器?當用戶訪問某個站點時,瀏覽器在發送請求前會到cookies.txt文件中查詢是否存在該站點的cookie信息,如果存在會在HTTP請求首部添加首部信息:cookie:"name=value",如果存在多個就會在HTTP請求中添加多個首部。
5.cookie文件有大小限制:每個瀏覽器都有些不同,不過大概都在4090字節左右,每個域名存放的cookie個數差別就比較大了,每個cookie大小也有限制,大約4K左右。
6.cookie的設置除了使用響應報文的方式也可以直接通過JS代碼設置:
document.cookie;//獲取當前域全部cookie信息 document.cookie = "id=00001"; console.log(document.cookie);//id=00001
在控制台查看:
同樣也可以設置cookie的屬性:
document.cookie = "id=00001;max-age=1000;";//設置cookie存儲時間1000秒,但是其時間是格林威治時間 document.cookie = "name=xiaoming; max-age=session;"//將max-age設置為session,就表示其為臨時cookie,當用戶將所有當前域的瀏覽器窗口關閉這個cookie就會刪除
有趣的是我的瀏覽器顯示的卻是這樣的:
被設置為session的cookie的時間卻是1969年12月31日23時59分59秒,在有的瀏覽器中顯示的就是session,但是這兩者沒有什么區別,都表示為臨時cookie,反而顯示時間為1969年的更反應了cookie的內部機制,瀏覽器是更具當前時間與cookie時間來判斷其是否過期,如果過期瀏覽器就會將其刪除,如果時間都在計算機元年之前了,當瀏覽器關閉窗口時肯定被瞬間秒殺了。
既然直接設置秒數的時間是在計算機元年上加上設置的時間,那怎么來設置cookie預期的過期時間呢?可以直接使用Date對象作為時間值,但是值得注意的是如果采用Date對象就不能使用max-age了,而是使用expires。
var date = new Date(); date.setDate(date.getDate()+3);//設置cookie過期時間是三天后 document.cookie = "cc=CC; expires=" + date +";";
所以,時間的設置又有了新的意義,如果某個cookie在過期之前因為業務的變化而過時了,而且cookie的個數有限,但是新的業務又需要設置新的cookie怎么辦呢?將之間設置為過期時間就OK了啊。比如上面的cc="CC":
document.cookie="cc=CC;max-age=-1;";
6.封裝一個cookie添加刪除的API:
1 var manageCookie = { 2 //name,alue, date(expires), path, domain, secure 3 //名稱/值, 過期時間, 路徑, 域名, 安全 4 setCookie:function(name,value,date,path,domain,secure){ 5 document.cookie = name + "=" + value + ";expires="+ date + ";" 6 +(path ? "path=" + path + ";" : "") 7 +(domain ? "domain=" + domain + ";" : "") 8 +(secure ? "secure=" + secure + ";" : ""); 9 return this; 10 }, 11 removeCookie:function(name){ 12 document.cookie = name + "=;max-age=-1"; 13 return this; 14 } 15 } 16 var date = new Date(); 17 date.setDate(date.getDate()+1); 18 manageCookie.setCookie("sss","SSS",date); 19 manageCookie.deleteCookie("sss");
最后還來一個cookie查找吧:
1 getCookie:function(name,callback){ 2 var arrCookies = document.cookie.split("; "); 3 for(var i = 0; i < arrCookies.length; i++){ 4 var itemCookie = arrCookies[i].split("="); 5 if(itemCookie[0] == name){ 6 callback(itemCookie[1]);//將找到的第一個匹配cookie的值傳給回調函數處理 7 break; 8 } 9 } 10 return this; 11 }
四、cookie的缺陷
1.由於cookie采用文本形式存在計算機本地,從信息安全角度來講非常的不安全,所以不能存儲敏感信息。
2.cookie可以人為的在瀏覽器其設置禁用,所以不能保證能有效支持相關功能實現
通過cookie實現頁面刷新的拖拽定位demo:

1 //css 2 #demo{ 3 position: absolute; 4 width: 100px; 5 height: 100px; 6 top: 100px; 7 left: 100px; 8 background-color: orange; 9 } 10 //html、JS 11 <div id="demo"></div> 12 <script> 13 var oDemo = document.getElementById('demo'); 14 var manageCookie = { 15 //name,alue, date(expires), domain, path, secure 16 //名稱/值, 過期時間,域名, 路徑, 安全 17 setCookie:function(name,value,date,path,domain,secure){ 18 document.cookie = name + "=" + value + ";expires="+ date + ";" 19 +(path ? "path=" + path + ";" : "") 20 +(domain ? "domain=" + domain + ";" : "") 21 +(secure ? "secure=" + secure + ";" : ""); 22 return this; 23 }, 24 removeCookie:function(name){ 25 document.cookie = name + "=;max-age=session"; 26 return this; 27 }, 28 getCookie:function(name,callback){ 29 var arrCookies = document.cookie.split("; "); 30 for(var i = 0; i < arrCookies.length; i++){ 31 var itemCookie = arrCookies[i].split("="); 32 if(itemCookie[0] == name){ 33 callback(itemCookie[1]);//將找到的第一個匹配cookie的值傳給回調函數處理 34 break; 35 } 36 } 37 return this; 38 } 39 } 40 var drag = { 41 //入口函數--啟動拖拽功能,為拖拽體綁定鼠標按下事件 42 //this指向功能管理對象 43 init:function(oDemo){ 44 this.dom = oDemo; 45 var _this = this; 46 this.bindEvent(); 47 manageCookie.getCookie("dragLeft",function(data){ 48 if(data){ 49 _this.dom.style.left = data + "px"; 50 } 51 }); 52 manageCookie.getCookie("dragTop",function(data){ 53 if(data){ 54 _this.dom.style.top = data + "px"; 55 } 56 }); 57 }, 58 //鼠標按下事件綁定--當鼠標按下時為document綁定鼠標移動事件 59 //this指向拖拽體DOM 60 bindEvent:function(){ 61 this.dom.onmousedown = this.mouseDown.bind(this); 62 }, 63 //鼠標移動、鼠標松開事件 64 //this指向功能管理對象 65 //實現鼠標按下時需要獲取的數據:鼠標位置,DOM位置 66 mouseDown:function(e){ 67 document.onmousemove = this.mouseMove.bind(this); 68 document.onmouseup = this.mouseUp.bind(this); 69 //將鼠標位置保存到功能管理對象drag,方便鼠標移動時取值 70 this.disY = e.clientY - this.dom.offsetTop; 71 this.disX = e.clientX - this.dom.offsetLeft; 72 }, 73 //鼠標移動事件回調函數 74 //this指向document 75 //鼠標移動時修改DOM位置--實現物體移動 76 mouseMove:function(e){ 77 //將時時的DOM位置保存到功能管理對象上,方便鼠標抬起時寫入cookie 78 this.newLeft = e.clientX - this.disX; 79 this.newTop = e.clientY - this.disY; 80 this.dom.style.left = this.newLeft + 'px'; 81 this.dom.style.top = this.newTop + 'px'; 82 }, 83 //鼠標松開事件回調函數 84 //this指向document 85 //當鼠標送時將鼠標移動事件取消--物體脫離鼠標 86 //鼠標松開事件也可以取消了。 87 //將DOM位置寫入cookie 88 mouseUp:function(){ 89 document.onmousemove = null; 90 document.onmouseup = null; 91 manageCookie.setCookie("dragLeft",this.newLeft,10000); 92 manageCookie.setCookie("dragTop",this.newTop,10000); 93 } 94 } 95 drag.init(oDemo); 96 </script>