Cookie和Session解析

   有些時候對cookiesession理解比較混亂,並且很有可能在面試的時候,也被經常提起cookiesession的區別以及使用。經過查閱一些資料,整理出以下文檔

一、cookiesession的概念

1、  cookie

   當一個用戶通過Http協議訪問一個服務器的時候,服務器會將一些key/value這樣的一些鍵值對返回給客戶端瀏覽器,並給這些數據加上一些限制條件,在相關的條件符合的情況下,瀏覽器再訪問服務器的時候,又會把這些數據完整的帶上,返回給服務器。由於HTTP協議是無狀態協議,通過cookie的這種方式,服務器就能知道客戶端從哪裏來的。並且在一些很短的時間呢,用戶的一些信息如果被頻繁訪問,這樣服務器就可以做一些緩存等優化,保證訪問的速度。

    Http協議中並沒有規定相關對cookie大小等的限制,但是由於各家瀏覽器在實現的過程中的不同,cookie的大小也不同,但是大概爲4K ,大多數瀏覽器對每個站點限制一般爲20cookie,當超過這個數量的時候,老的cookie將會被覆蓋掉。Cookie在生成的時候,會指定一個expire的值,指定cookie的過期時間,時間超過以後,此Cookie將不能再被使用。必須生成新的cookie,在我們訪問網站的時候,通常會見到保存密碼多長時間這個選項,如下圖:

wKiom1XYla2iCv2HAACFUEIfk-s323.jpg


  實際上我們登錄的這些信息被存儲到了客戶端瀏覽器中,然後通過這個cookie來保存我們個人的登錄信息,這樣我們在下次訪問的時候就不需要再重新輸入用戶名和密碼進行登陸。但是當超過設置的expire時間以後,就無法再使用。

  java程序中,我們可以如下代碼設置和使用cookie

public String getCookie(Cookie[] cookies,String key){
      if(cookies!=null){
         for(Cookie cookie:cookies){
            if(cookie.getName().equals(key)){
                returncookie.getValue();
            }
         }
      }
      retur nnull;
 }
   publicvoiddoHello(HttpServletRequest request,HttpServletResponse response){
      Cookie[]cookies= request.getCookies();
      
      StringuserName= getCookie(cookies,"username");
      if(userName==null){
         response.addCookie(new Cookie("username","zhangsan"));
      }
      
      response.getHeader("Set-Cookie");
 }


Tomcat創建Set-cookie相應頭的時序圖

wKiom1XYlgGjZ-kaAAFEeCG_qQE301.jpg

   從以上時序圖中我們可以看出,在我們通過response.addCooke創建多個Cookie,我們在每次創建Cookie時,都會創建一個以nameSet-CookieMimeHeaders.並且在服務器返回給客戶端的時候也不會對相同Header標識的Set-Cookie進行合併。Tomcat源碼中可以看出,這段代碼位於org.apache.coyote.http11.Http11Processor類的prepareResponse方法中。如下:

Int size = headers.size();
for(int i=0;i<size;i++){
   outputBuffer.setHeader(headers.getName(i),headers.getValue(i));
}

   這段代碼清楚的表示,在構Http返回字節流時,是將Header中的所有項順序的寫出,沒有做任何修改,所以可以想象瀏覽器在接受HTTP協議返回的數據時是分別解析每一個Header項的。


2、  session

cookie可以讓服務端程序跟蹤每個客戶的訪問,但是每次客戶端的訪問都必須回傳這些cookie的值,如果cookie很多,這樣就無形的增加了客戶端與服務端的數據量傳輸,而Session的出現正是爲了解決這個問題。

  同一個客戶端每次和服務端進行交互時,不需要每次都需要回傳所有的Cookie的值,而只需要傳回一個ID,這個ID是客戶端在第一次訪問服務端的時候生成的,而每個客戶端都是唯一的,這樣每一個客戶端就生成了一個唯一的ID,客戶端只需要傳回這個ID就行了,這個ID通常是NAME爲JSSIONID的一個Cookie.所以說Session通常是基於Cookie來工作的,當然當客戶端禁用cookie的時候,還有其他的方式進行實現Session,但是就Session和Cookie的關係來說,Session基於Cookie進行工作。


二、session的調用過程

  有了Session ID 的服務端就可以創建HttpSession對象,第一次觸發通過調用rquest.getSession()方法,如果當前的Session ID還沒有對應的HttpSession對象,則會創建一個HttpSession對象。並將這個對象加到org.apache.catalina.Manager

的session容器中保存,Manager類將會管理所有Session的生命週期,Session過期將會被銷燬,服務器關閉,Session將會被序列化到磁盤等。只要這個HttpSession對象存在,用戶就可以根據SessionId來獲取這個對象,也就達到了狀態保持的問題。以下是Session創建的時序圖


wKioL1XYmPbBz6_XAAMOmwjDT68943.jpg


三、cookie的安全問題

   雖然CookieSession都是可以跟蹤客戶端的訪問記錄,但是他們的工作方式顯然是不同的。Cookie通過把所有要保存的數據通過HTTP西醫的頭部從客戶端傳遞到服務器,又從服務器傳遞給客戶端,所有的數據都存儲到客戶端的瀏覽器裏。所以這些Cookie數據是可以被訪問到的。我們通過Firefox是可以訪問到記錄到瀏覽器端的用戶名和密碼的。例如我的百度賬號,如下圖:

wKioL1XYmSTyCwzoAAG5IEmj7v4940.jpg


wKioL1XYmTPRiyz0AAFg0qa3J80637.jpg


不僅可以查看Cookie,我們甚至可以通過一些工具添加,修改Cookie,所以Cooike的安全性是不可保證的。相比較而言,Session的安全性要高很多,因爲Session是將數據保存在服務端,指示通過Cookie傳遞一個JSESSIONID而已。所以Session更適合存儲用戶隱私和重要數據。

四、分佈式session實現思路

    在我們應用在進行部署的時候,現在大多數情況均不是單機部署,而是進行集羣的部署,但是這樣會導致客戶端訪問的時候,如果一臺服務器掛掉,這樣保存在這臺服務器上的session就會消失,導致客戶登錄等相關信息丟失,降低了客戶體驗的良好性。爲了解決以上問題,基本上會有下面兩種思路:

  • 在各臺服務器間session複製共享

Session複製共享,主要指在集羣環境下,各臺應用服務器之間進行同步session,使得session保持一致。當一臺服務器出現問題時候,負載均衡服務器會把請求負載到另外的一臺服務器,由於每臺服務器均存儲所有服務器的session,這樣可以保證請求的連續性。

但是這種方案會有以下不足

  • 技術比較複雜,必須在同一種中間件中進行實現,例如tomcat

  • Session的複製必定會帶來性能上的損失,特別是當應用服務器比較多,session存儲的內容比較大時。

  • Session內容的序列化,會導致服務器性能下降

  • Session通過廣播或者其他形式同步到其他服務器。不管是內網還是外網,同樣對網絡會造成壓力,使之成爲瓶頸。

  • 使用session服務器,基於redis等緩存服務器

這種思想是在服務器本機存儲一份session,然後再在緩存服務器中存儲一份session,當服務器發生故障,在本機找不到session時,可以去緩存服務器中去尋找,再複製到本地,此種爲業界常用思路。

wKioL1XYmWTSdTLOAAFSQ4qHLD0365.jpg

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章