前言
HTTP 是一種無狀態的協議,爲了分辨鏈接是誰發起的,需要自己去解決這個問題。不然有些情況下即使是同一個網站每打開一個頁面也都要登陸一下。而Session 和Cookie 就是爲了解決這個問題而提出來的兩個機制。
應用場景
-
登陸網站,今天輸入用戶名密碼登錄了,第二天再打開很多情況下就直打開了。這個時候用到的一個機制就是cookie。
-
session 一個場景是購物車,添加了商品之後客戶端處可以知道添加了哪些商品,而服務端如何判別呢,所有也需要存儲一些信息就用到了session。
1.Cooke
- 通俗講,是訪問某些網站後在本地存儲的一些網站相關信息,下次訪問時減少一些步驟。更準確的說法是:Cookie 是服務器在本地機器上存儲的小段文本並隨每一個請求發送至同一服務器,是在客戶端保持狀態的方案。
- Cookie的主要內容包括:名字,值,過期時間,路徑和域。使用Fiddler抓包就可以看見,比方說我們打開百度的某個網站可以看到Headers包括Cookie,如下:
BIDUPSID: 9D2194F1CB8D1E56272947F6B0E5D47E
PSTM: 1472480791
BAIDUID: 3C64D3C3F1753134D13C33AFD2B38367:FG
ispeed_lsm: 2
MCITY: -131:
pgv_pvi: 3797581824
pgv_si: s9468756992
BDUSS: JhNXVoQmhPYTVENEdIUnQ5S05xcHZMMVY5QzFRNVh5SzZoV0xMVDR6RzV-bEJZSVFBQUFBJCQAAAAAAAAAAAEAAACteXsbYnRfY2hpbGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALlxKVi5cSlYZj
BD_HOME: 1
H_PS_PSSID: 1423_21080_17001_21454_21408_21530_21377_21525_21193_21340
BD_UPN: 123253
sug: 3
sugstore: 0
ORIGIN: 0
bdime: 0
- key, value形式。過期時間可設置的,如不設,則瀏覽器關掉就消失了,存儲在內存當中,否則就按設置的時間來存儲在硬盤上的,過期後自動清除,比方說開關機關閉再打開瀏覽器後他都會還存在,前者稱之爲Session cookie 又叫 transient cookie,後者稱之爲Persistent cookie 又叫 permenent cookie。路徑和域就是對應的域名,a網站的cookie自然不能給b用。
2.Session
-
存在服務器的一種用來存放用戶數據的類HashTable結構。
-
瀏覽器第一次發送請求時,服務器自動生成了一 HashTable 和一 Session ID 來唯一標識這個 HashTable,並將其通過響應發送到瀏覽器。瀏覽器第二次發送請求會將前一次服務器響應中的Session ID 放在請求中一併發送到服務器上,服務器從請求中提取Session ID,並和保存的所有Session ID 進行對比,找到這個用戶對應的HashTable。
一般這個值會有時間限制,超時後毀掉這個值,默認30分鐘。 -
當用戶在應用程序的Web 頁間跳轉時,存儲在 Session 對象中的變量不會丟失而是在整個用戶會話中一直存下去。
-
Session的實現方式和CooKie有一定關係。建立一個連接就生成一個session ID,打開幾個頁面就好幾個了,這裏就用到了Cookie,把session id存在Cookie中,每次訪問的時候將 session id帶過去就可以識別了。
區別
- 存儲數據量方面:session 能夠存儲任意的java對象,cookie只能存儲 String 類型的對象。
- 一個在客戶端一個在服務端。因Cookie在客戶端所以可以編輯僞造,不是十分安全。
- Session 過多時會消耗服務器資源,大型網站會有專門 Session 服務器,Cookie存在客戶端沒問題。
- 域的支持範圍不一樣,比方是 a.com 的 Cookie 在 a.com下都能用,而 www.a.com的Session 在 api.a.com下都不能用,解決這個問題的辦法是 JSONP或者跨域資源共享。
Session 多服務器間共享
- 服務器實現的 session 複製或 session 共享,如 webSphere 或 JBOSS在搭建集羣時配置實現 session複製或session共享,致命缺點:不好擴展和移植。
- 利用成熟技術做session複製,如12306使用的gemfire,如常見內存數據庫Redis或 memcached ,雖然較普適但依賴第三方。
- 將session維護在客戶端,利用 cookie ,但客戶端存在 風險數據不安全,且可以存放的數據量較小,所以將 session 維護在客戶端還要對 session 中的信息加密。
- 第二種方案和第三種方案的合體,可用 gemfire實現 session 複製共享,還可將 session 維護在 Redis中實現 session 共享,同時可將 session 維護在客戶端的cookie中,但前提是數據要加密。
這三種方式可迅速切換,而不影響應用正常執行。在實踐中,首選 gemfire 或者 redis 作爲 session 共享的載體,一旦 session 不穩定出現問題的時候,可以緊急切換 cookie 維護 session 作爲備用,不影響應用提供服務。
單點登錄中,cookie被禁用了怎麼辦?(一點登陸,子網站其他系統不用再登陸)
- 單點登錄的原理是後端生成了一個 session ID ,設置到 cookie,後面所有請求瀏覽器都會帶上 cookie,然後服務端從cookie 獲取 session id,查詢到用戶信息。
- 所以,保持登錄的關鍵不是 cookie,而是通過 cookie保存和傳輸的 session id,本質是能獲取用戶信息的數據。
- 除了cookie,還常用 HTTP 請求頭來傳輸。但這個請求頭瀏覽器不會像 cookie一樣自動攜帶,需要手工處理。