面試總結 Cookie 和 Session

2021-10-10 11:22:59 字數 3111 閱讀 1780

cookie是 web 伺服器傳送給瀏覽器的一塊資訊,瀏覽器會在本地乙個檔案中給每個 web 伺服器儲存 cookie。以後瀏覽器再給特定的 web 伺服器傳送請求時,同時會傳送所有為該伺服器儲存的 cookie。

session是儲存在 web 伺服器端的一塊資訊。session 物件儲存特定使用者會話所需的屬性及配置資訊。當使用者在應用程式的 web 頁之間跳轉時,儲存在 session 物件中的變數將不會丟失,而是在整個使用者會話中一直存在下去。

cookie 和session 的不同點:

資料量比較小,所以將session 維護在客戶端還要對 session 中的資訊加密。

我們實現的方案可以說是第二種方案和第三種方案的合體,可以利用 gemfire 實現 session 複製共享,還可以將session 維護在redis 中實現 session 共享,同時可以將 session 維護在客戶端的 cookie 中,但是前提是資料要加密。這三種方式可以迅速切換,而不影響應用正常執行。我們在實踐中,首選 gemfire 或者 redis 作為 session 共享的載體,一旦session 不穩定出現問題的時候,可以緊急切換 cookie 維護 session 作為備用,不影響應用提供服務。

這裡主要講解 redis 和 cookie 方案,gemfire 比較複雜大家可以自行檢視 gemfire 工作原理。利用 redis 做session 共享,首先需要與業務邏輯**解耦,不然 session 共享將沒有意義,其次支援動態切換到客戶端 cookie 模式。redis 的方案是,重寫伺服器中的 httpsession 和 httpservletrequest,首先實現 httpsession 介面,重寫 session的所有方法,將 session 以 hash 值的方式存在redis 中,乙個session 的 key 就是 sessionid,setatrribute 重寫之後就是更新 redis 中的資料,getattribute 重寫之後就是獲取 redis 中的資料,等等需要將 httpsession 的介面一一實現。

實現了 httpsesson,那麼我們先將該 session 類叫做 mysession(當然實踐中不是這麼命名的),當 mysession 出現之後問題才開始,怎麼能在不影響業務邏輯**的情況下,還能讓原本的 request.getsession()獲取到的是mysession,而不是伺服器原生的session。這裡,我決定重寫伺服器的httpservletrequet,這裡先稱為myrequest,但是這可不是單純的重寫,我需要在原生的 request 基礎上重寫,於是我決定在 filter 中,實現 request 的偷梁換柱, 我的思路是這樣的,myrequest 的構建器,必須以 request 作為引數,於是我在 filter 中將伺服器原生的 request(也有可能是框架封裝過的 request ) , 當做引數 new 出來乙個 myrequest , 並且 myrequest 也實現了httpservletrequest 介面,其實就是對原生 request 的乙個增強,這裡主要重寫了幾個 request 的方法,但是最重要的是重寫了 request.getsession(),寫到這裡大家應該都明白為什麼重寫這個方法了吧,當然是為了獲取 mysession,於是這樣就在filter 中,偷偷的將原生的request 換成myrequest 了,然後再將替換過的request傳入chan.dofilter(), 這樣 filter 時候的**都使用的是 myrequest 了,同時對業務**是透明的,業務**獲取 session 的方法仍然是request.getsession(),但其實獲取到的已經是 mysession 了,這樣對 session 的操作已經變成了對redis 的操作。這樣實現的好處有兩個,第一開發人員不需要對 session 共享做任何關注,session 共享對使用者是透明的;第二,filter 是可配置的,通過filter 的方式可以將 session 共享做成一項可插拔的功能,沒有任何侵入性。

這個時候已經實現了一套可插拔的session 共享的框架了,但是我們想到如果 redis 服務出了問題,這時我們該怎麼辦呢,於是我們延續 redis 的想法,想到可以將 session 維護在客戶端內(加密的 cookie),當然實現方法還是一樣的,我們重寫 httpsession 介面,實現其所有方法,比如 setattribute 就是寫入 cookie,getattribute 就是讀取cookie,我們可以將重寫的 session 稱作 mysession2,這時怎麼讓開發人員透明的獲取到 mysession2 呢,實現方法還是在filter 內偷梁換柱,在 myrequest 加乙個判斷,讀取 sessiontype 配置,如果 sessiontype 是 redis 的,那麼 getsession 的時候獲取到的是mysession,如果 sessiontype 是 coolie 的,那麼 getsession 的時候獲取到的是mysession2,以此類推,用同樣的方法就可以獲取到 mysession 3,4,5,6 等等。

這樣兩種方式都有了,那麼我們怎實現兩種 session 共享方式的快速切換呢,剛剛我提到乙個 sessiontype,這是用來決定獲取到session 的型別的,只要變換sessiontype 就能實現兩種session共享方式的切換,但是sessiontype 必須對所有的伺服器都是一致的,如果不一致那將會出現比較嚴重的問題,我們目前是將 sessiontype 維護在環境變數裡,如果要切換 sessiontype 就要重啟每一台伺服器,完成 session 共享的轉換,但是當伺服器太多的時候將是一種災難。而且重啟服務意味著服務的中斷,所以這樣的方式只適合伺服器規模比較小,而且使用者量比較少的情況,當伺服器太多的時候,務必需要一種協調技術,能夠讓伺服器能夠及時獲取切換的通知。基於這樣的原因,我們選用zookeeper 作為配置平台,每一台伺服器都會訂閱 zookeeper 上的配置,當我們切換 sessiontype 之後,所有伺服器都會訂閱到修改之後的配置,那麼切換就會立即生效,當然可能會有短暫的時間延遲,但這是可以接受的。

單點登入的原理是後端生成乙個 session id,然後設定到 cookie,後面的所有請求瀏覽器都會帶上 cookie, 然後服務端從 cookie 裡獲取 session id,再查詢到使用者資訊。所以,保持登入的關鍵不是 cookie,而是通過cookie 儲存和傳輸的 session id,其本質是能獲取使用者資訊的資料。除了 cookie,還通常使用 http 請求頭來傳輸。但是這個請求頭瀏覽器不會像 cookie 一樣自動攜帶,需要手工處理。

Python爬蟲之Cookie和Session

關於cookie和session估計很多程式設計師面試的時候都會被問到,這兩個概念在寫web以及爬蟲中都會涉及,並且兩者可能很多人直接回答也不好說的特別清楚,所以整理這樣一篇文章,也幫助自己加深理解 其實簡單的說就是當使用者通過http協議訪問乙個伺服器的時候,這個伺服器會將一些name value...

Django框架之Cookie和Session元件

cookie是伺服器傳送到使用者瀏覽器並儲存在本地的一小塊資料,它會在瀏覽器下次向同一伺服器再發起請求時被攜帶併發送到伺服器上。通常,它用於告知服務端兩個請求是否來自同一瀏覽器,如保持使用者的登入狀態。cookie 使基於無狀態的 http 協議記錄穩定的狀態資訊成為了可能。1 會話狀態管理 如使用...

Django之元件 cookie與session

cookie 由伺服器產生,存放在客戶端瀏覽器上的鍵值對。設定值 取值 request.cookies.get key request.cookies key 刪除值 session 儲存在伺服器上的鍵值對。設定值 request.session key value request.session ...