淺談Cookie與Session

  前幾天接觸了一個實現自動登陸的項目,其中涉及到了Cookie和Session的相關知識,突然發現,雖然本身常用Cookie和Session,但對二者的原理和聯繫卻知之甚少,特寫一篇博客來總結一下。html

Cookie

Cookie的產生背景

  在web應用中,會話跟蹤是很重要的。一個用戶的全部請求操做都應該屬於同一個會話。 例如,在網上商城中,用戶A購買的商品都應該放在A的購物車內,而不能放在用戶B或C的購物車內,由於它們不屬於同一個會話。
  衆所周知,web應用是使用HTTP協議傳輸數據的,而HTTP協議是無狀態的。這裏稍微解釋一下HTTP協議的無狀態特性:瀏覽器的每一次請求,服務器都會獨立處理,不與以前或以後的請求產生關聯,也就是說,瀏覽器的每一次請求,對服務器來講都是全新的。這個過程能夠用下圖說明:
web

圖片未加載成功
   一旦數據交換完畢,客戶端與服務器端的鏈接就會關閉,再次交換數據須要創建新的鏈接,這就意味着服務器沒法從鏈接上跟蹤會話。 即用戶A購買了一件商品放入購物車內,當再次購買商品時,服務器已經沒法判斷該購買行爲是屬於用戶A的會話仍是用戶B的會話了。要跟蹤該會話,必須引入一種機制,因而Cookie就應運而生了。Cookie由W3C組織提出,最先由Netscape社區發展,目前全部的主流瀏覽器都支持Cookie。

Cookie的工做原理

  上面說到因爲HTTP協議的無狀態特性,服務器沒法從鏈接上知道客戶身份。解決辦法就是給客戶端頒發一個「通行證」,不管誰訪問都必須攜帶本身的通行證,這樣服務器就能從通行證上確認客戶身份了,這就是Cookie的工做原理。
  Cookie其實是一小段文本信息。客戶端請求服務器,若是服務器須要記錄該用戶狀態,就使用response向客戶端瀏覽器頒發一個Cookie,在Servlet中即調用response.addCookie(Cookie cookie)方法。客戶端瀏覽器會把Cookie保存起來,當瀏覽器再次請求該網站時,瀏覽器把請求的網址連同該Cookie一同提交給服務器,服務器檢查該Cookie,從而得到用戶身份信息。服務器還能夠根據須要修改Cookie的內容。跨域

Cookie的機制

  Cookie機制採用的是在客戶端保持狀態的方案。 當服務器調用addCookie方法向瀏覽器頒發Cookie,本質上是在HTTP的響應頭中加上一行特殊的指示以提示瀏覽器按照指示生成相應的Cookie,保存在客戶端,裏面記錄着用戶當前的信息。當用戶再次訪問服務器時,瀏覽器檢查全部存儲的Cookie,若是某個Cookie所聲明的做用範圍大於等於將要請求的資源所在的位置,則把該Cookie附在請求資源的HTTP請求頭上發送給服務器,服務器根據該Cookie得到用戶身份信息。瀏覽器

Cookie相關問題

Cookie的生命週期

  在討論Cookie的生命週期以前,先說一下setMaxAge(int maxAge)方法,該方法用於設置Cookie的失效時間。
  若是maxAge爲正數,則表示該Cookie會在maxAge秒以後自動失效。瀏覽器會將maxAge爲正數的Cookie持久化,即寫到對應的Cookie文件中。不管客戶關閉了瀏覽器仍是電腦,只要還在maxAge秒以前,登陸網站時該Cookie仍然有效。
  若是maxAge爲負數,則表示該Cookie僅在本瀏覽器窗口以及本窗口打開的子窗口內有效,關閉窗口後該Cookie即失效。maxAge爲負數的Cookie,爲臨時性Cookie,不會被持久化,不會被寫到Cookie文件中。Cookie信息保存在瀏覽器內存中,所以關閉瀏覽器該Cookie就消失了。Cookie默認的maxAge值爲–1。tomcat

Cookie的修改和刪除

  Cookie並不提供修改、刪除操做。若是要修改某個Cookie,只須要新建一個同名的Cookie,添加到response中覆蓋原來的Cookie便可。
  若是要刪除某個Cookie,能夠將Cookie的maxAge屬性設置爲0;也能夠新建一個同名的Cookie,並將maxAge設置爲0,並添加到response中覆蓋原來的Cookie。maxAge爲0的Cookie即失效Cookie,會被瀏覽器從Cookie文件或者內存中刪除。
  注意:修改、刪除Cookie時,新建的Cookie除value、maxAge以外的全部屬性,例如name、path、domain等,都要與原Cookie徹底同樣。不然,瀏覽器將視爲兩個不一樣的Cookie不予覆蓋,致使修改、刪除失敗。安全

Cookie的不可跨域名性

  不少網站都會使用Cookie,例如,Google會向客戶端頒發Cookie,Baidu也會向客戶端頒發Cookie。可是瀏覽器訪問Google只會攜帶Google的Cookie,而不會攜帶Baidu的Cookie;Google也只能操做Google的Cookie,而不能操做Baidu的Cookie。這是由Cookie的隱私安全機制決定的,隱私安全機制可以禁止網站非法獲取其餘網站的Cookie,即Cookie的不可跨域名性。
  Cookie在客戶端是由瀏覽器來管理的,瀏覽器可以保證Google只會操做Google的Cookie而不會操做Baidu的Cookie,從而保證用戶的隱私安全。瀏覽器判斷一個網站是否能操做另外一個網站Cookie的依據是域名,Google與Baidu的域名不同,所以Google不能操做Baidu的Cookie。
  須要注意的是,用戶登陸網站 www.google.com 以後會發現訪問 images.google.com 時登陸信息仍然有效,兩者雖然同屬於Google,可是域名不同,一樣不能互相操做彼此的Cookie,這是由於Google作了特殊處理。想讓同一個一級域名下的兩個二級域名能交互使用Cookie,須要設置Cookie的domain參數。例如想全部 wsghawk.com 名下的二級域名均可以使用該Cookie,能夠這麼寫:cookie.setDomain(".wsghawk.com"); 注意,domain參數必須以點(".")開始。服務器

Cookie的路徑

  domain屬性決定容許訪問Cookie的域名,而path屬性決定容許訪問Cookie的路徑(ContextPath)。例如,若是隻容許/hawk/下的程序使用Cookie,能夠這麼寫:cookie.setPath("/hawk/"); 設置爲「/」時容許全部路徑使用Cookie,path屬性須要使用符號「/」結尾。cookie

Session

Session的工做原理

  Session是另外一種記錄客戶狀態的機制,不一樣的是Cookie保存在客戶端瀏覽器中,而Session保存在服務器上。客戶端瀏覽器訪問服務器的時候,服務器把客戶端信息以某種形式記錄在服務器上,這就是Session。客戶端瀏覽器再次訪問時只須要從該Session中查找該客戶的狀態就能夠了。
  若是說Cookie機制是經過檢查客戶身上的「通行證」來肯定客戶身份的話,那麼Session機制就是經過檢查服務器上的「客戶明細表」來確認客戶身份。Session至關於程序在服務器上創建的一份客戶檔案,客戶來訪的時候只須要查詢客戶檔案表就能夠了。dom

Session的機制

  Session機制採用的是在服務器端保持狀態的方案。 當用戶訪問到一個服務器,服務器就要爲該用戶建立一個Session,在建立這個Session的時候,服務器首先檢查這個用戶發來的請求裏是否包含了一個SessionId,若是包含了一個SessionId則說明以前該用戶已經登錄過併爲此用戶建立過Session,那服務器就按照這個SessionId把這個Session在服務器的內存中查找出來(若是查找不到,就有可能爲它新建立一個)。若是客戶端請求裏不包含有SessionId,則爲該客戶端建立一個Session並生成一個與此Session相關的SessionId。這個SessionId是一個惟一的、不重複的字符串,這個SessionId將被在本次響應中返回到客戶端保存,而保存這個SessionId的正是Cookie。 這樣在交互過程當中瀏覽器能夠自動的按照規則把這個標識發送給服務器。網站

Session相關問題

Session的生命週期

  以前我一直認爲,一個瀏覽器窗口被打開是建立一個Session,而關閉瀏覽器窗口時該Session就會被刪除,其實這是錯誤的! 實際上直到某服務器端程序調用 HttpServletRequest.getSession(true); 這樣的語句時Session才被建立。而除非程序通知服務器刪除Session,不然Session會被服務器一直保留,直到Session的失效時間到了自動刪除。服務器是不知道瀏覽器是否被關閉的。
  以前會產生這種錯覺的緣由是:通常Session機制都使用Cookie來保存SessionId,而一旦關閉瀏覽器,SessionId就不存在了,再鏈接服務器時就找不到原來的Session了。若是服務器設置的Cookie被保存到硬盤上,或者使用某種手段改寫瀏覽器發出的HTTP請求頭,把原來的SessionId發送給服務器,則再次打開瀏覽器仍然可以找到原來的Session。因爲關閉瀏覽器不會致使Session被刪除,迫使服務器爲Seesion設置了一個失效時間,當距離客戶端上一次使用Session的時間超過這個失效時間時,服務器就能夠認爲客戶端已經中止了活動,纔會把Session刪除以節省存儲空間。
  通常狀況下,Session都是存儲在內存裏,當服務器進程被中止或者重啓的時候,內存裏的Session也會被清空。若是設置了Session的持久化特性,服務器就會把Session保存到硬盤上,當服務器進程從新啓動或這些信息將可以被再次使用(tomcat在shutdown前默認會自動將Session保存到指定的目錄中,所以tomcat從新啓動後,Session是能夠繼續使用的)。

Session對瀏覽器的要求

  SessionId爲服務器自動生成的,它的maxAge屬性通常爲–1,表示僅當前瀏覽器內有效,而且各瀏覽器窗口間不共享,關閉瀏覽器就會失效。所以同一機器的兩個瀏覽器窗口訪問服務器時,會生成兩個不一樣的Session。可是由瀏覽器窗口內的連接、腳本等打開的新窗口(也就是說不是雙擊桌面瀏覽器圖標等打開的窗口)除外,這類子窗口會共享父窗口的Cookie,所以會共享一個Session。注意:新開的瀏覽器窗口會生成新的Session,但子窗口除外,子窗口會共用父窗口的Session。
  洋洋灑灑寫了很多了,其實目前企業流行的方式仍是在請求頭中攜帶token來進行身份驗證,由於Session會佔用服務器較多的內存空間,影響效率。其實最後還應該寫一寫Servlet中與Cookie和Session有關的API,但感受以我這種事無鉅細的辦事風格又要寫好久,仍是你們本身去查閱參考文檔吧<(^-^)>!
  如對文章內容有疑問或發現其中的錯誤,請在評論區留言。

參考文章

WEB應用中的SESSION知多少?
Cookie/Session機制詳解

相關文章
相關標籤/搜索