拜託!不要再問我Session與Cookie的區別了

從我剛開始學程序時這一題就常出如今面試考題裏,一直到如今都仍是能看見這個問題。ios

這個問題重要嗎?我以爲蠻重要的。由於 Session 所表明的是「狀態」,若是沒有了狀態,一大堆功能都會失效。面試

對於工程師來講必須去理解什麼是 Session,以及如何操做它,而 Cookie 就是這之中很重要的一環。redis

所以這會是一系列的文章,我稱之爲 Session 與 Cookie 三部曲,會由淺入深,從不一樣的面向去看 Session 與 Cookie。算法

這是系列文的第一篇,想用簡單白話的方式通俗地跟你們解釋什麼是 Session,什麼又是 Cookie,目標是但願沒有任何技術背景的人也可以看懂。數據庫

要向沒有技術背景的人講這種概念性的東西,用一堆專有名詞絕對是最差勁的作法。瀏覽器

而最好的作法一般是舉一個現實生活中很貼近的例子,藉由這種方式比較能讓毫無技術背景的讀者們去理解這究竟是個什麼東西。服務器

所以,咱們從經營雜貨店開始吧!微信

小明の雜貨店cookie

四十歲的退休之後在家閒得發慌,每一天都過得毫無目標並且渾渾噩噩。網絡

「退休之後不是應該無憂無慮嗎?」小明也是這樣問本身的,但沒辦法,他深知本身的個性就是這樣,沒辦法閒下來,必定要作點事情才行。

因而,小明就用了退休金在家裏附近的巷口開了間雜貨店,而且取名爲:「小明の雜貨店」,是個毫無創意的名稱,但把本身的名字放在招牌上一直是他的夢想。

小明平時人緣還算不錯,在倒垃圾時會與旁邊的婆婆媽媽閒聊,說着那個誰誰誰的兒子考上了臺大,誰誰誰的女兒最近交了個男朋友,成爲左鄰右舍八卦網絡的一部分。

不僅婆婆媽媽,連年輕的那一代也對他感受不錯,八成是由於他很識相地不會硬要跟年輕人尬聊,看到他們都只是簡單點個頭示意一下,而不是像其餘人劈頭就把私事全都問了一遍。

所以在開幕那天,雜貨店比如 Apple Store 開幕通常(除了沒有人特意前一天就跑來排隊之外),周遭的鄰居們都跑來捧場,把整個店擠得風雨不透,單日營收甚至上百萬(臺幣)。

第一天就能有如此成績,可見人緣是多麼重要的一件事。有人緣,有人潮;有人潮,有錢潮。

但開幕畢竟是開幕,一般都是一家商店這輩子的巔峯,除非有跳樓大拍賣(假的那種不算,例如說天天都在大拍賣的)或是週年慶,否則都很難超越了。

隨着日曆一張張被撕開,店裏的生意慢慢恢復正常,仍是喜歡傳統便利商店的都跑回去便利商店了,而嫌遠懶得走這麼多路的則選擇雜貨店消費。

看似步上正軌的雜貨店,問題卻隨着時間慢慢浮上臺面。

臉盲症的困擾

小明身爲雜貨店的店長兼惟一的店員,全部大小事都是他一我的在處理。傳統雜貨店跟便利商店最大的差異在哪裏?在於人情味。

就像是你去菜市場買菜的時候會被說帥哥或美女,或者是去買早餐的時候老闆會問你:「同樣?」,你只要點個頭就好了。這些人與人之間的情感是不管信息怎麼發展都沒法取代的。

但是小明沒有辦法,由於他根本記不起來是同一我的。

每個來店裏的人對小明來講都是一個獨立的個體,是徹底不相干的。你可能會疑惑說:「就算認不出臉,認聲音、衣服、氣味也均可以吧?」,看來你是過低估小明瞭。

小明不僅認不出臉,他什麼都認不出來。我也不知道小明到底哪裏出了差錯,小明本身也不知道。

但總之就是這樣,就算你天天來,天天穿着同樣的衣服,用着同樣的聲音,他都認不出來你是同一我的。

講一個例子你就知道了,有一次有個顧客結完賬之後把發票忘在櫃檯,一出店門口才想起來,就馬上跑回去拿。

結果小明徹底沒認出來是同一我的,還覺得這人是想來偷拿發票的,跟他確認過買的品項一致之後才願意把發票還給他。

對,就是這麼誇張,小明每一次結帳都是在幫一個全新的人結帳。

在生活上或許沒什麼問題,反正小明無依無靠也沒朋友,本身一我的生活慣了,但是在經營雜貨店上面就有很大的問題了。

除了會讓人以爲很沒有人情味之外,最大的問題就是有些顧客的需求他沒辦法處理。

有些人逛雜貨店喜歡慢慢挑慢慢選嘛,而後有些物品可能又很重,或者是在結帳的時候才忽然想起來還要買什麼,這時候就會把東西先放在收銀臺那裏,本身跑回去拿其餘品項。

我前面已經提過了,小明認人的能力是零,當客人拿新的物品回去收銀臺的時候,小明已經認不出他來了。

所以他不知道收銀臺上面那些物品是誰的,客人也很難跟小明證實說:「對,這些是我剛剛想買的」。

這個使用者體驗簡直差到不行,所以店裏的生意每況愈下,只有那種果斷型顧客會來消費(一進雜貨店就往本身的目標走,拿完以後馬上結帳的那種)。

小明固然注意到了這個情況,也知道不能再這樣下去了,繼續這樣的話大概不用兩個月店就會倒了。因而小明冥思苦想,快思慢想,東想西想,終於想到了一個解決方法。

方法雖老舊但有用

前面有提到太小明最大的問題是「每一個客人都是新的客人」,他沒辦法認出他們是同一個客人,因此天然也沒法記住他們的「狀態」,而這個纔是最大的問題。

山不轉路轉,路不轉頭轉,既然小明本身沒辦法記住狀態,寫張紙條不就得了嗎?

當你在收銀臺結帳的時候寫一張紙條給你,上面寫着:「五香乖乖x一、義美鮮奶茶x1」,而後你就能夠回去挑其餘你想要的東西,當你再回來收銀臺的時候把這張紙條給小明,小明就知道這些東西是你的。

或者你是個常客,每次來都買同樣的東西,小明就在結帳時寫給你一張紙條,把你常買的東西全都寫上去,這樣下次結帳時你只要帶那一張紙條過來,小明就知道你常買什麼了!

你有看過那種悽美愛情電影嗎?男女主角其中一方得了罕見疾病,天天都會完全失憶一次,另外一方就會在家裏幫他寫滿便條紙,透過那些便條紙,主角才能知道本身是誰、對方是誰,以及本身到底發生了什麼事。

對,你能夠把小明想象成就是失憶的那個,而便條紙就是給客人的紙條。既然本身記不住,就讓這些紙條代勞,把狀態放在上面。

雖說客人要把紙條留着其實蠻不方便的,但前面說太小明人緣其實不錯,所以常客都會看在他的面子上把紙條帶着,讓這個機制得以繼續運做。而小明店裏的生意也所以好轉一點點。

對,只有一點點而已,由於隨身攜帶一張紙條實在是太麻煩了,因此也沒多少人會這樣作。

再繼續往下講以前,咱們先進入中場休息。

中場休息

讓咱們先從比喻回到網絡世界裏,HTTP 是無狀態的,因此每個 Request 都是不相關的,就像是對小明來講每一位客人都是新的客人同樣,他根本不知道誰是誰。

既然你沒辦法把他們關聯,就表明狀態這件事情也不存在。

把左邊換成顧客,右邊換成小明也依然成立。多一個得是我多打了,但我懶得修。

那怎麼辦呢?在故事裏咱們用紙條來解決這件事情,小明會在結帳時寫下紙條並遞給客人,客人下次只要再帶着紙條過來,小明就知道發生什麼事了。

小紙條功不可沒

小明最大的問題就是他本身沒辦法記憶「狀態」,所以須要倚靠一個機制來幫他管理「狀態」,而這個機制咱們就叫作 Session。

本來對小明來講,每個客人都是新的客人,彼此之間毫無關聯,因此也沒有任何狀態可言。

但有了紙條之後,兩個在小明眼中徹底不一樣的客人被關聯了起來,小明就能夠知道:「原來這個新的客人是之前那個來買木材的客人!」

因此 Session 是什麼?就是一種讓 Request 變成 Stateful 的機制。以小明的例子來講,Session 就是一種讓客人之間能互相關聯起來的機制。

小明靠紙條來實做 Session 機制,那在網絡世界中能夠靠什麼呢?舉一個最簡單的例子,網址!

讓咱們假設有個購物網站的網址是:market.tw,當你把蘋果加入購物車的時候,你實際上是送一個 Request 給服務器,而後服務器會把你導到 market.tw?

item1=apple,接着你再把火山硅肺病加入購物車,網址就會變成:market.tw?item1=apple&item2=pneumonoultramicroscopicsilicovolcanoconiosis

最後你按下結帳,服務器就靠着你地址欄上的信息來判斷你的狀態是什麼,在這個例子中就等同於看你的購物車裏面有什麼。

簡單來講呢,地址欄上的信息就是小明故事中的紙條,是儲存狀態的地方。而上述例子 Client 與 Server透過地址欄上的狀態來實做 Session 機制。

好,中場休息差很少到這邊要結束了。這一段是想先拉回網絡的部分,從本來故事中的比喻切回真實世界網絡的運做模式,以及先讓你們理解 Session 究竟是個什麼東西。

在接下來的故事裏面,小明會碰到更多更多的問題,他能迎刃而解嗎?讓咱們繼續看下去。

到底誰會隨身攜帶紙條?

前面已經有提過了,儘管小明靠着這個紙條的機制留住了一些常客,可是新客人呢?有多少人會願意爲了再來這間店而特意留下具備狀態的紙條?

基本上沒有,由於這樣子太麻煩了!

有天小明在快要入眠時,忽有一龐然大物拔山倒樹而來,蓋一靈感也。他想到了一個絕妙的 idea:「不會有人隨身攜帶紙條,但總會隨身攜帶手機吧!」

因而流程就變成這樣子:

  • 客人來店裏消費,小明結帳時請他拿出手機,並在手機裏面留了一些信息
  • 客人第二次來店裏,小明看看手機裏有沒有以前本身留下的信息

先不用管到底小明把信息放在手機的哪裏,這不是重點;重點是手機裏的信息取代了之前的紙條,客人不用刻意再帶一個沒有用的紙條了,只須要把原本就會隨身攜帶的手機拿出來就好,跟之前相比方便許多。

好,接下來咱們終於要講到標題的第二個東西了:Cookie。Cookie 是什麼?Cookie 就是故事裏面存在手機的信息。

想要知道真正使用 Cookie 的流程,你只要把上面的客人用「瀏覽器」來取代,小明用「服務器」來取代,就是答案了:

  • 瀏覽器發送一個 Request 給 Server,Server 叫瀏覽器設置 Cookie,瀏覽器便把這些數據存在 Cookie 裏面。
  • 瀏覽器帶着 Cookie 一塊兒發 Request 給 Server,Server 根據 Cookie 的內容決定狀態。

此次沒有買火山硅肺病了

雖然在現實生活中不是每一個人都會隨身攜帶手機,可是每一個瀏覽器都會把 Cookie 一併帶上去,也會按照 Server 的指令來儲存 Cookie。

你能夠把 Cookie 稱做是一個機制,Server 能夠利用 Set-Cookie 這個語法讓瀏覽器儲存一些內容,而這些內容會在瀏覽器發送 Request 時一併送上來。

而瀏覽器裏儲存的那些內容也叫作 Cookie,就是咱們故事中所提的小紙條或者是存在手機裏的信息。

前面有提過 Session 機制能夠只靠地址欄操做,跟 Cookie 能夠一點關係都沒有。

但在實際應用上,Session 之因此經常跟 Cookie 綁在一塊兒,就是由於靠 Cookie 來操做 Session 機制的話很是方便。

或者應該這樣說,Cookie 原本就是爲了操做 Session 而生的。藉由標準化的規範,制定了一個專門用來讓瀏覽器與 Server 交換數據的機制。

若是用故事來比喻,就比如政府制定說每一個人隨身必定要攜帶手機,而後手機裏面必定要存小明留下來的狀態。

這邊再來作個簡單的總結:

Session 是什麼?就是一種讓 Request 變成 Stateful 的機制。以小明的例子來講,Session 就是一種讓客人之間能互相關聯起來的機制。在故事裏面咱們用了紙條跟手機裏的信息來比喻,有多種方式能夠達成 Session。

在網絡世界中,也有不少種方式能夠來操做 Session,前面介紹過第一種是地址欄,第二種就是靠 Cookie。而 Cookie 就是存在瀏覽器裏的一些信息。

講到這邊,差很少就把 Session 與 Cookie 的定義與介紹講完了,但故事還沒完呢,咱們還有最後一個問題要來解決。

咖啡寄杯的煩惱

雖然店裏生意還能夠,但小明無時無刻不想着怎麼樣發大財賺大錢,讓店裏的生意變得更好。

他觀察到最近好多便利商店開始賣起了咖啡,並且時不時就買一送一或是第二件半價,而且貼心地提供了寄杯的服務。

寄杯就是指說你今天先喝一杯,剩下那杯我幫你記着,你下次來的時候跟我講我再給你。

若是不提供這種服務,那買一送一就必定要兩我的才能喝了(或是你馬上喝兩杯),根本就是排擠像小明這樣的邊緣人。秉持着將心比心的原則,小明固然是但願提供寄杯服務的。

那該怎麼寄呢?照以前那樣不就得了嗎?本來客人的手機裏面會存着消費習慣之類的東西,如今多存一個還有幾杯咖啡不就好了?

例如說客人買兩杯只喝一杯,就在上面寫着:coffee=1,表明還剩一杯咖啡,下次來的時候只要出示這個信息,就再給他一杯。

聽起來十分合理,並且小明也這樣作了,店裏的生意變得更好,買咖啡的人越來越多,靠着咖啡就讓單月營收翻了兩倍。

一切看似很是順利,直到小明月底對賬的時候:不對啊,爲何買咖啡的數量只有 55 杯,賣出去的卻有 66 杯?

一貫很相信人的小明,在那一瞬間見識到了人心的險惡之處。沒錯,有人本身偷改信息,例如說把 coffee=1 加個幾劃改爲 coffee=7,就得到了額外六杯的免費咖啡。

這些奧步讓小明狠狠一晚上之間變成了大人,絕望的小明把悲憤轉化成力量,只花了三個晚上就想到了兩個解決方法。

第一個方法最簡單,就是隻要把存在客人手機上的信息加密就行了。

例如說本來是 coffee=1,通過小明自制的特殊加密算法以後,會變成 ED85B89167A84B631C10B046B5FB7FC0 這串只有小明知道怎麼解開的密文。

這樣一來,除非客人能夠破解這段密碼,不然信息就不可能被竄改。但有一個小缺點,那就是當小明想存的信息越來越多以後,這一串字也會越來越長,就會在客人的手機裏面佔更大的容量。

這個容量是有上限的,客人不會把整臺手機都給你存這些信息,因此這點要特別注意。

這個方法解決問題的思路是這樣的:「既然存在手機上的信息會被竄改,那我讓他不能改就好」。

而第二個方法解決問題的思路是這樣的:「既然存在手機上的信息會被竄改,那我把信息存在我這邊不就行了嗎?」

與其把那些消費習慣或是寄杯數量存在客人的手機裏,不如把這些東西記在個人筆記本里面,而且用一種方式把這兩個信息對應起來,這樣就不怕數據會被改動了。

舉例來講,小明能夠在筆記本寫下客人的身份證字號跟相關資訊,例如說:「A111111111 coffee=1」,接着小明只在客人的手機裏面存「A111111111」。

下次客人再來消費的時候,就透過身份證字號去筆記本里面查,就知道客人到底還剩幾杯咖啡了。

因爲小明的筆記本天天下班都會鎖在保險箱裏面,所以不用懼怕被偷或是被改,能夠假設它必定是準確的。

而這樣子的方式不把主要信息存在客人那裏,而是存在本身這裏,因此也不會有被竄改的風險。

但是有個問題,若是有人把身份證字號改爲其餘人的怎麼辦?那不就破功了嗎?就能夠僞造其餘人的身份。

這個簡單,不如不要用身份證字號,用一個 16 位數的英數字混合亂碼好了,例如說:A59Uhe7I94J330mN,這樣就很難被猜到了吧!

因而流程會變成這樣:

客人那編只須要報 ID 便可,其餘資訊都在小明那裏

跟以前同樣,他們都是透過一張紙條或者是手機裏的信息來溝通,但惟一的差異是客人跟小明之間只透過 A59Uhe7I94J330mN 這個存在手機裏的 ID 來驗證身份,其餘相關資訊都寫在小明的筆記本里面。

這種驗證的方法就像是我曾經去過的網咖。由於會員打咖比較便宜嘛,一小 60 變成一小 36,不辦白不辦,就辦了一張會員卡。店員特別說明認卡不認人,必定要出示卡片才行。

我只要去打咖的時候出示這張會員卡,店員就知道我曾經消費過多少錢,也知道我喜歡點的餐點,全部的信息都是存在他們的系統裏面,而個人身份就是透過這張會員卡來表示。

寄杯的例子中,會員卡就是 A59Uhe7I94J330mN 這個 ID,網咖的電腦系統就是小明的筆記本。

小明最後決定用第二種方法,也就是這種靠 ID 認人的方式來管理客人的狀態。

今後以後就沒有客人可以竄改信息了,而寄杯服務也運行的十分順利,真是皆大歡喜,可喜可賀。

至於後來變得生意太好,讓小明開了分店之後碰到的那些問題,就又是另一段故事了。

儲存狀態的方式

小明的故事說完了,該來把上面這一段變成網絡的實際案例了。其實在網絡世界中問題也是同樣的。

前面已經提到過咱們會把狀態存在 Cookie 裏面,讓 Request 之間可以變得有關聯。

假設咱們今天要來作一個會員系統,那我要怎麼知道這個 Request 表明的是哪個會員?

最直覺的方式就是登入之後把會員賬號存在 Cookie 裏面嘛,這樣不就知道是誰了嗎?

但是會碰到的問題就跟寄杯的故事同樣,Cookie 裏的東西是能夠被竄改的,若是我改爲了別人的會員賬號,我就能夠僞造他的身份登入了!

解決方法跟上面寄杯的解法同樣:

第一個解法就是把 Cookie 裏面的內容給加密,這樣就沒法被竄改了。這種方式就稱之爲 Cookie-based session,意思就是你把全部的 Session 狀態都存在 Cookie 裏面。

因此不要把「用 Cookie 來操做 Session 機制」跟「Cookie-based session」搞混了,二者是不同的。

至於缺點的話前面有提到,Cookie 的大小是有限制的,超過大小的話瀏覽器就不幫你存了。

所以當你想存的信息愈來愈多,Cookie 固然也愈來愈大,就有可能超過這個限制。

或者是哪天你的加密方式以及密鑰被黑客破解,那黑客同樣能夠僞造任何人的身份。

第二個解法就是透過一個 ID 來辨識身份,這個 ID 稱之爲 Session Identifier,簡稱 Session ID。

Server 只在 Cookie 裏面存一個 Session ID,其他的狀態都存在 Server 那邊,我習慣把 Server 那邊的數據稱爲 Session Data:

其實就是小明筆記本的翻版而已

Session ID 的產生方式跟前面說的同樣,一般會是一個沒法猜想的隨機數。

你可能會想說:「很難猜是一回事,但機率不是 0 啊!」,對,的確是有機率可以猜到,可是那個機率過低過低了(例如說幾千億分之一之類的)。

並且 Server 在你亂猜猜錯幾回以後就有可能把你 ban 掉不讓你繼續猜,因此沒什麼問題。

不過這邊要特別注意的一點是 Session ID 基本上是種認證不認人的方式,也就是說一旦你的 Session ID 被偷走,別人就能夠僞造你的身份來登陸了。而這個 Session ID 一般都是保存在 Cookie 之中。

這就是爲何有些網站發生駭客入侵的情形以後你會忽然被註銷,由於黑客可能偷到一批 Session ID,這時候服務器就會把全部 Session 數據所有清空。

以故事來比喻就是把筆記本丟掉,買一本新的,這樣被偷走的那些 Session ID 就沒用了,而 Server 找不到你的 Session ID,天然就沒法登入,所以把你給註銷了。

網站發生問題時客服會要你先把 Cookie 清掉也是相似的道理,由於 Cookie 跟狀態有關,有時候可能程序有一些 Bug,把你導到了錯誤的狀態,把 Cookie 清空等於把狀態清空,從新再開始,就有可能變得正常。

總結

其實我本來覺得我很懂 Cookie 跟 Session,但越研究愈加現好像不是這麼一回事,只是我自我感受良好而已。

但把該看的數據都看完一遍以後,再讓本身沉澱個幾天,大體上就能徹底理解整個脈絡的發展。

Session 是什麼?就是一種讓 Request 變成 Stateful 的機制。以小明的例子來講,Session 就是一種讓客人之間能互相關聯起來的機制。

在故事裏面咱們用了紙條跟手機裏的信息來比喻,有多種方式能夠達成 Session。

在網絡世界中,也有不少種方式能夠來實做 Session,前面介紹過第一種是地址欄,第二種就是靠 Cookie,而 Cookie 就是存在瀏覽器裏的一些信息。

常見的錯誤認知是必定要有 Cookie 才能實做 Session,這是錯誤的。

有了 Session 以後,會碰到數據被竄改的問題,這時候有兩種解決方式:

  • 一個是 Cookie-based session,意思是你照舊把狀態存在 Cookie,可是加密之後再存。
  • 另外一個方法是把狀態存在 Server 端,靠一個 Session ID 來辨識,這個狀態你能夠存成檔案,能夠存在內存裏,也能夠存在數據庫,只是實做方式的不一樣而已,但原理都是同樣的。

而這個狀態儲存的地方在口語上也會被稱之爲「Session」,例如說:「幫我把 user id 存在 Session 裏」,或者是「註銷記得把 Session 清空」之類的。

因此在實際用法中,我認爲 Session 之因此很差理解是由於太多地方用到同一個詞,但倒是在指代不一樣的東西(但是又很相似)。跟 API 有點像,太多地方都用到這個詞了。

做者:胡立
出處:https://medium.com/@hulitw/se...

關注 民工哥技術之路 微信公衆號對話框回覆關鍵字:1024 能夠獲取一份最新整理的技術乾貨:包括系統運維、數據庫、redis、MogoDB、電子書、Java基礎課程、Java實戰項目、架構師綜合教程、架構師實戰項目、大數據、Docker容器、ELK Stack、機器學習、BAT面試精講視頻等。

相關文章
相關標籤/搜索