? ? ? ?首先什么是session,字面意思是會(huì)話(huà)控制。個(gè)人理解就是就是一套可以識(shí)別用戶(hù)的系統(tǒng),為什么需要一套叫做session的東西來(lái)識(shí)別用戶(hù)呢?這就得從http協(xié)議說(shuō)起,http協(xié)議是基于TCP/IP協(xié)議的一層封裝(為了讓大家都容易理解一些,我都以直白的方式來(lái)說(shuō),盡量不扯太底層的東西)。用戶(hù)在訪問(wèn)一個(gè)網(wǎng)站的時(shí)候,每一次請(qǐng)求頁(yè)面之后都是斷開(kāi)連接的,既然是斷開(kāi)連接的,那么我下一次訪問(wèn)的時(shí)候服務(wù)器哥怎么知道是我再一次訪問(wèn)呢?最簡(jiǎn)單的方式,第一次我給一個(gè)憑證你,這個(gè)憑證記錄著一些與身份相關(guān)的信息,第二次你訪問(wèn)的時(shí)候給我看這個(gè)憑證,我就知道你是之前的那個(gè)用戶(hù)了。
憑證的交付
? ? ? ?既然我們知道用`憑證`這一個(gè)辦法可以識(shí)別用戶(hù),那么好了,我們就要想辦法給用戶(hù)一個(gè)憑證。怎么給也是一個(gè)技術(shù)活,一個(gè)最簡(jiǎn)單的辦法:把憑證信息都放在cookie就行了,反正用戶(hù)每次訪問(wèn)都會(huì)帶著cookie訪問(wèn)的。
制作憑證
? ? ? ? 既然知道如何給用戶(hù)憑證了,那么服務(wù)器哥就很開(kāi)心啦(可以識(shí)別用戶(hù)咯),趕緊就開(kāi)始制作憑證,一開(kāi)始就直接把用戶(hù)信息直接放到cookie里面(姓名:小明,性別:男,年齡不詳),這個(gè)時(shí)候把憑證給了小明,然后每一次小明都拿這個(gè)憑證給服務(wù)器哥看,然后就可以愉快的玩???。
憑證的信任危機(jī)
? ? ? ? 一開(kāi)始服務(wù)器哥非常相信用戶(hù),沒(méi)想到有一天,某個(gè)用戶(hù)竟然在憑證上偽造了內(nèi)容,讓服務(wù)器哥誤認(rèn)為他是某個(gè)用戶(hù)(這個(gè)時(shí)候憑證是明文,該起來(lái)非常方便),然后被偽造的那個(gè)用戶(hù)的信息泄漏了。。。信息無(wú)價(jià)吶,服務(wù)器哥怎么可能讓這事情蔓延下去,所以服務(wù)器哥立馬把憑證內(nèi)容加密了(這個(gè)加密是可逆加密),這個(gè)時(shí)候用戶(hù)拿到的是一堆看不懂的數(shù)據(jù),不過(guò)服務(wù)器哥自己可以解密,用戶(hù)也無(wú)法偽造憑證,這樣子就解決了一下憑證的信任危機(jī)。(python的flask框架就是這樣子處理的)
憑證內(nèi)容保密問(wèn)題
? ? ? ?雖然服務(wù)器哥加密了憑證的內(nèi)容,然而畢竟是可以解密的,假如有一些信息不希望用戶(hù)看到的,但是為了方便又想寫(xiě)在憑證上面怎么辦呢。這個(gè)時(shí)候,服務(wù)器哥想到給用戶(hù)的憑證只記錄一個(gè)唯一的編碼,然后在自己這里放著用戶(hù)憑證的具體數(shù)據(jù),然后為這個(gè)數(shù)據(jù)關(guān)聯(lián)編碼就好了。
憑證保存問(wèn)題
? ? ? ? ?既然憑證信息放在服務(wù)器哥這里,那么又該怎么存放呢。服務(wù)器哥想了幾套解決方案出來(lái):
(1)基于文件的存儲(chǔ)
(2)基于數(shù)據(jù)庫(kù)的存儲(chǔ)
(3)基于內(nèi)存的存儲(chǔ)
(4)基于memcached的存儲(chǔ)
(5)基于redis的存儲(chǔ)
? ? ? ?基于文件的存儲(chǔ),我們只需要簡(jiǎn)單的以用戶(hù)拿到的唯一編碼作為文件名就好,具體信息放在文件里面(我之前寫(xiě)的paas系統(tǒng)就是用了這種方案:https://github.com/yubang/app/blob/master/middle/session.py)。這種方案有幾個(gè)缺點(diǎn),首先磁盤(pán)讀寫(xiě)速度并不快,然后憑證的唯一編碼有過(guò)期時(shí)間,隨著時(shí)間的流失,廢棄的文件也會(huì)越來(lái)越多,所以還要定時(shí)刪除過(guò)期的文件。并且在多臺(tái)服務(wù)器的時(shí)候,還要保持每臺(tái)服務(wù)器都能讀取到這些文件。
? ? ? ?基于數(shù)據(jù)庫(kù)的存儲(chǔ),這種方案跟基于文件差不多,比文件的優(yōu)點(diǎn)是有多臺(tái)服務(wù)器的時(shí)候,只要連著一臺(tái)數(shù)據(jù)庫(kù)就可以保證讀取到這些數(shù)據(jù)。
? ? ? ?基于內(nèi)存的存儲(chǔ)這方案主要優(yōu)點(diǎn)是讀寫(xiě)數(shù)據(jù)比較快,然而內(nèi)存斷電后數(shù)據(jù)都沒(méi)了,并且程序之間內(nèi)存獨(dú)立了(不過(guò)linux系統(tǒng)有一個(gè)/dev/shm的目錄是映射到內(nèi)存的),并且多服務(wù)器時(shí)候讀取數(shù)據(jù)也是一個(gè)問(wèn)題,過(guò)期數(shù)據(jù)也要手動(dòng)清除。
? ? ? ?基于memcached這種方案其實(shí)跟內(nèi)存差不多,然而memcached幫我們解決了除了斷電數(shù)據(jù)丟失之外的大部分問(wèn)題,在數(shù)據(jù)超過(guò)一定量時(shí)候刪除一些數(shù)據(jù),支持多臺(tái)服務(wù)器來(lái)讀取數(shù)據(jù)。
? ? ? ? 基于redis這種方案其實(shí)是擁有了memcached的優(yōu)點(diǎn),并且斷電后數(shù)據(jù)還保存數(shù)據(jù)(哈哈,服務(wù)器哥再也不擔(dān)心斷電咯)
憑證交付難題
? ? ? ? 技術(shù)路總是困難重重的,服務(wù)器哥好不容易依靠cookie交付憑證,解決了各種安全問(wèn)題。突然有一天,一個(gè)用戶(hù)說(shuō)我不使用cookie的(服務(wù)器哥哭暈了),用戶(hù)又不能得罪的,怎么辦呢?左想右想(技術(shù)總有替代方案的),終于找到幾個(gè)辦法:
(1)每次請(qǐng)求都在url附帶上唯一編碼(哈哈,好辦法)【類(lèi)似于我們平時(shí)調(diào)用第三方API】
(2)每次訪問(wèn)在headers附帶上唯一編碼(也是辦法)
故事結(jié)局
? ? ? ?不知不覺(jué)這個(gè)故事就說(shuō)完了,最后就是服務(wù)器哥利用一張憑證成功記住了用戶(hù)。
? ? ? ?總的來(lái)說(shuō),session就是給每一個(gè)用戶(hù)一個(gè)隨機(jī)的唯一的編號(hào),交付途徑可以是cookie,url或者h(yuǎn)eaders。而通過(guò)這個(gè)唯一的編碼,映射到服務(wù)器存儲(chǔ)的具體信息,保存方案各種各樣有磁盤(pán)有內(nèi)存。
題外話(huà)
技術(shù)是無(wú)味的,代碼只是一堆字符,然而代碼制作的產(chǎn)品卻是令人振奮的,我只想以最簡(jiǎn)單有趣的話(huà)解說(shuō)最無(wú)味的底層技術(shù),如果喜歡的話(huà),點(diǎn)贊是對(duì)我最好的支持。