最近想要實作「收藏到我的最愛」的功能。
提到這個功能,我腦中第一個想到的就是「Web Storage API」。但正當我打算找相關的資料來看時,突然又想到好像還有個叫「Cookie / Session」的玩意兒?
既然都決定要學了,那不如就一次弄清楚吧,所以這次參考了 Huli 的 文章 想來做一份關於「Cookie / Session」的筆記。
認識無狀態
要了解為什麼需要 Session 與 Cookie 之前,要先知道 HTTP 是一種「無狀態」的協議。
什麼叫無狀態?直接看例子:
1 | 瀏覽器:安安,我是 PeaNu,我現在要登入哦 |
你看,每當你想要做下一步的時候,Server 就已經忘記你是誰了。換句話說,每一次的 Request 都是不相關的。
PeaNu 登入時是一個 Request,要查看購物車商品也是一個 Request,但不管 PeaNu 發了幾次 Request,對 Server 而言,每一次都是一個全新的 Request,因為 Server 沒辦法記住當時的「狀態」。
解救失憶症的好夥伴 Session
「Session」是一個可以讓 Server 記住每一次 Request 狀態的機制。
實作 Session 的方式有很多種,其中一種方法是「網址」:
1 | 瀏覽器:我要買蘋果,把蘋果加到購物車 ( market.tw?item1=apple ) |
另外一種方式是利用 「Cookie」。
每個瀏覽器都有 Cookie ,一個用來儲存資料的東西。
現在假設每個瀏覽器都隨身攜帶一個幸運餅乾(幸運餅乾是美國的一種餅乾,裡面通常會塞著一張紙條,可以參考這裡):
1 | 瀏覽器:嗨,給我一個豬排 |
從 Cookie-based 到 Session Identifier
在前面的例子裡,我們把資料都儲存在瀏覽器的 Cookie 中,這個方法稱為「Cookie-based session(以 Cookie 為基礎的 Session)」
在理解什麼是「Session Identifier」之前,我們可以先思考一下使用 Cookie 有什麼問題?為什麼會有 Session Identifier 的出現?
有一件很重要的事情要知道,那就是「Cookie 是可以被竄改的」:
1 | 瀏覽器:嗨,我要買咖啡,寄 10 杯 |
這個時候,如果瀏覽器自己修改 Cookie 的值,就會變成這樣:
1 | 瀏覽器:(對幸運餅乾的紙條動手腳,改成 coffee = 20) |
為了解決 Cookie 被擅自竄改的問題,第一個會直覺想到的方法是:把 Cookie 中的資料做加密處理。
所以 Server 在設置 Cookie 的時候,可以先用一個加密的方式來產生資料,再把加密過後的資料存到 Cookie 裡:
1 | 瀏覽器:嗨,我要買咖啡,寄 10 杯 |
這時候如果瀏覽器想要竄改 Cookie 的值,就得先破解這套加密的演算法,才有辦法做修改。
這樣的做法確實解決了 Cookie 被擅自竄改的問題,但這依舊屬於 Cookie-based session。
這樣子做有什麼問題嗎?實際上是有的,因為 Cookie 能夠儲存的資料量是有限的(4KB),所以當要儲存在 Cookie 的資料越來越多時,很容易就會超出上限值。
為了解決這個問題,「Session Identifier」就誕生了。
它背後的原理是這樣子:
Server 現在不把資料儲存在瀏覽器的 Cookie 了,而是都儲存在 Server 這邊。至於 Cookie 則只會儲存一個用來辨識身分的識別碼,透過這個識別碼,Server 就可以在自己的記事本上找到對應的資料。
1 | 瀏覽器:嗨,我要買咖啡,寄 10 杯 |
當下一次瀏覽器來領咖啡時:
1 | 瀏覽器:嗨,我來領我的咖啡 |
儲存在 Cookie 中的識別碼稱為「SessionID」。
這樣子就解決了 Cookie 大小限制的問題,因為不論有多少資料要儲存,cookie 唯一要儲存的資料都只有識別碼(SessionId)。
不過有一點要特別提醒的是:Server 只認 SessionId 不認人。也就是說,不管是誰,只要他的 Cookie 中的 SessionId 可以對應到 Server 中儲存的資訊,那他就可以取得相對應的資料。
總結
最後,試著問自己這些問題,看看自己有沒有真的理解:
- HTTP 的無狀態是什麼意思?
- Session 是用來做什麼的?
- 怎麼實作 session?
- Cookie-base Session 跟 Cookie 有什麼差異?
- Cookie-base Session 會有什麼問題,session Identifier 又是用來解決什麼問題?
答案都在內文裡了,如果忘記了就在去裡面找答案吧。