Session會話與Cookie簡單說明

散盡浮華發表於2018-02-22

 

Facebook、 Gmail、 Twitter 是我們每天都會用的網站(LCTT 譯註:才不是呢)。它們的共同點在於都需要你登入進去後才能做進一步的操作。只有你通過認證並登入後才能在 twitter 發推,在 Facebook 上評論,以及在 Gmail上處理電子郵件。經常有人會疑惑:Session會話與Cookies的區別是什麼?使用者登入的原理是什麼?網站是如何認證的?它怎麼知道是哪個使用者從哪兒登入進來的?下面將對這些問題進行一一解答。

1)session與cookie的簡單區別
session和cookie本質上確實是兩個東西,但cookie同時也是session id的載體,cookie儲存session id。

cookie資料存放在使用者的瀏覽器上,session資料放在網站的伺服器上。
session儲存在伺服器端與瀏覽器設定無關,cookie在客戶端並受瀏覽器設定限制。
cookie是在你的電腦瀏覽器上儲存的,session是在網站伺服器上的. 也就是說你換一個電腦你的cookie就不起作用了, 而session只要你的瀏覽器不關就還能訪問到.
通常的都是兩者結合著用的. cookie的話你自己就可以通過對瀏覽器的設定禁用掉.這樣就不起作用了

cookie不是很安全,別人可以分析存放在本地的cookie並進行cookie欺騙,考慮到安全應當使用session。
session是伺服器端快取,cookie是客戶端快取。
cookie機制採用的是在客戶端保持狀態的方案,而session機制採用的是在伺服器端保持狀態的方案

session會在一定時間內儲存在伺服器上。當訪問增多,會比較佔用你伺服器的效能,考慮到減輕伺服器效能方面,應當使用cookie。
session是伺服器保持客戶端狀態資訊的方案,一般是儲存在伺服器中的一塊記憶體中,session超時時間在伺服器端進行設定。
cookie是客戶端保持使用者資訊的方案,一般是檔案形式儲存,cookie清空時間是在客戶端瀏覽器設定。
從開發角度說,session資訊可以通過技術方案寫到客戶端儲存,cookie中的使用者資訊,也可以在使用者訪問該網站時,通過技術手段自動更新使用者的session資訊。

單個cookie儲存的資料不能超過4K,很多瀏覽器都限制一個站點最多儲存20個cookie。

建議:將登陸資訊等重要資訊存放為session;其他資訊如果需要保留,可以放在cookie中

2)使用者登入的原理是什麼?
每次使用者在網站的登入頁面中輸入使用者名稱和密碼時,這些資訊都會傳送到伺服器。伺服器隨後會將你的密碼與伺服器中的密碼進行驗證。
如果兩者不匹配,則你會得到一個錯誤密碼的提示。如果兩者匹配,則成功登入。

3)使用者登入時發生了什麼?
登入後,web 伺服器會初始化一個會話session並在你的瀏覽器中設定一個 cookie 變數。該 cookie 變數用於作為新建會話的一個引用。
搞暈了?讓我們說的再簡單一點。

4)會話的原理是什麼?
伺服器在使用者名稱和密碼都正確的情況下會初始化一個會話。會話的定義很複雜,可以把它理解為“關係的開始”

認證通過後,伺服器就開始跟使用者展開一段關係了。由於伺服器不能象我們人類一樣看東西,它會在我們的瀏覽器中設定一個 cookie 來將我們的關係從其他人與伺服器的關係標識出來。

什麼是 Cookie?
cookie 是網站在使用者的瀏覽器中儲存的一小段資料。當使用者登入後,伺服器為使用者建立一段關係或者說一個會話,然後將唯一標識這個會話的會話 id 以 cookie 的形式儲存在使用者的瀏覽器中。所有這些東西存在的原因在於識別出使用者來,這樣當使用者寫評論或者發推時,伺服器能知道是誰在發評論,是誰在發推。當使用者登入後,會產生一個包含會話 id 的 cookie。這樣,這個會話 id 就被賦予了那個輸入正確使用者名稱和密碼的人了。也就是說,會話 id 被賦予給了擁有這個賬戶的人了。之後,所有在網站上產生的行為,伺服器都能通過他們的會話 id 來判斷是由誰發起的。

如何讓使用者保持登入狀態?
會話有一定的時間限制。這一點與現實生活中不一樣,現實生活中的關係可以在不見面的情況下持續很長一段時間,而會話具有時間限制。使用者必須要不斷地通過一些動作來告訴伺服器使用者還線上。否則的話,伺服器會關掉這個會話,而使用者會被登出。不過在某些網站上可以啟用"保持登入"功能,這樣伺服器會將另一個唯一變數以 cookie 的形式儲存到我們的瀏覽器中。這個唯一變數會通過與伺服器上的變數進行對比來實現自動登入。若有人盜取了這個唯一標識(我們稱之為 cookie stealing),他們就能訪問使用者的賬戶了。

========================擴充套件======================
1) 由於Http協議是無狀態的,服務端如何識別客戶端請求呢,只能依靠http報文中新增部分頭欄位來實現請求識別(如何在請求body或這引數中設定會員引數,伺服器端會話就與自定義的會員識別繫結到一起)
2) 基於瀏覽器的web應用,請求都是有瀏覽器發起的,貌似也不能手動隨便新增請求頭(僅有XMLHttpRequest可以手動設定請求頭),哪有沒有一種可以由服務端生成,客戶端請求是自動在請求中設定對應頭欄位的技術呢,這就是cookie

Cookie:
cookie是在客戶端負責儲存的,既可以客戶端生成,也可以伺服器端生成,Cookie總是儲存在客戶端中,按在客戶端中的儲存位置,可分為記憶體Cookie和硬碟Cookie:
1)記憶體Cookie由瀏覽器維護,儲存在記憶體中,瀏覽器關閉後就消失了,其存在時間是短暫的
2)硬碟Cookie儲存在硬碟裡,有一個過期時間,除非使用者手工清理或到了過期時間,硬碟Cookie不會被刪除
3)cookie一些重要的屬性,path,domain,maxAge,secure,httponly,可以自己去研究一下
4)服務端生成cookie的響應頭為 Set-Cookie:JSESSIONID=164A9B3B768FD959AA20505D4C09; Path=/; HttpOnly
5)客戶端傳送http請求帶的cookie請求頭 Cookie:AMCV_niwodai%40AdobeOrg=-15069…7-badf-4795-9c64-eb9960c23d48

Session的實現原理:
1)服務端首先查詢對應的cookie的值(sessionid)
2)根據sessionid,從伺服器端session儲存中獲取對應id的session資料,進行返回
3)如果找不到sessionid,伺服器端就建立session,生成sessionid對應的cookie,寫入到響應頭中

session共享實現(如tomcat session會話共享)
傳統的session由伺服器端生成並儲存,當應用進行分散式叢集部署的時候,如何保證不同伺服器上session資訊能夠共享呢?
兩種實現方式:1.session集中儲存(redis,memcached,hbase等),2. 不同伺服器上session資料進行復制,兩種方式的優缺點,大家應該一目瞭然

基於session集中儲存的實現方案:
1)新增Filter,攔截請求,包裝HttpServletRequest
2)改寫getSession方法,從session儲存中獲取session資料,返回自定義的HttpSession實現
3)在生成新Session後,寫入sessionid到cookie中

Redis儲存session的需要考慮問題:
1) session資料如何在Redis中儲存?
2) session屬性變更何時觸發儲存?

實現思路:
考慮到session中資料類似map的結構,採用redis中hash儲存session資料比較合適,如果使用單個value儲存session資料,不加鎖的情況下,就會存在session覆蓋的問題,因此使用hash儲存session,每次只儲存本次變更session屬性的資料,避免了鎖處理,效能更好.
如果每改一個session的屬性就觸發儲存,在變更較多session屬性時會觸發多次redis寫操作,對效能也會有影響,我們是在每次請求處理完後,做一次session的寫入,並且之寫入變更過的屬性
如果本次沒有做session的更改, 是不會做redis寫入的,僅當沒有變更的session超過一個時間閥值(不變更session重新整理過期時間的閥值),就會觸發session儲存,以便session能夠延長有效期

相關文章