Session 與 Cookie 是什麼?

最近想要實作「收藏到我的最愛」的功能。

提到這個功能,我腦中第一個想到的就是「Web Storage API」。但正當我打算找相關的資料來看時,突然又想到好像還有個叫「Cookie / Session」的玩意兒?

既然都決定要學了,那不如就一次弄清楚吧,所以這次參考了 Huli 的 文章 想來做一份關於「Cookie / Session」的筆記。

認識無狀態

要了解為什麼需要 Session 與 Cookie 之前,要先知道 HTTP 是一種「無狀態」的協議。

什麼叫無狀態?直接看例子:

1
2
3
4
瀏覽器:安安,我是 PeaNu,我現在要登入哦
Server:好,你是 PeaNu,你成功登入了。
瀏覽器:我是PeaNu,我想看看我的購物車的商品
Server:不好意思,你哪位?

你看,每當你想要做下一步的時候,Server 就已經忘記你是誰了。換句話說,每一次的 Request 都是不相關的。

PeaNu 登入時是一個 Request,要查看購物車商品也是一個 Request,但不管 PeaNu 發了幾次 Request,對 Server 而言,每一次都是一個全新的 Request,因為 Server 沒辦法記住當時的「狀態」。

解救失憶症的好夥伴 Session

「Session」是一個可以讓 Server 記住每一次 Request 狀態的機制。

實作 Session 的方式有很多種,其中一種方法是「網址」:

1
2
3
4
5
瀏覽器:我要買蘋果,把蘋果加到購物車 ( market.tw?item1=apple )
瀏覽器:我要買豬排,把豬排加到購物車 ( market.tw?item1=apple&item2=cutlet )
瀏覽器:我要結帳
Server:查看網址後得知,item1=apple(蘋果),item2=cutlet(豬排)
Server:哦!你要買蘋果跟豬排。

另外一種方式是利用 「Cookie」。

每個瀏覽器都有 Cookie ,一個用來儲存資料的東西。

現在假設每個瀏覽器都隨身攜帶一個幸運餅乾(幸運餅乾是美國的一種餅乾,裡面通常會塞著一張紙條,可以參考這裡):

1
2
3
4
5
6
7
8
9
10
11
12
瀏覽器:嗨,給我一個豬排
Server:好,幸運餅乾借我,我儲存一下資料
Server:(把紙條塞到幸運餅乾裡)(set-Cookie: item1=apple)
Server:OK。

瀏覽器:阿,我還想要一個豬排
Server:好,幸運餅乾借我,我儲存一下資料
Server:(把紙條塞到幸運餅乾裡)(set-Cookie: item2=cutlet)

瀏覽器:好了,我要結帳(帶著幸運餅乾)
Server:把幸運餅乾拆開。(找到 apple 跟 cutlet)
Server:好的,你的蘋果跟豬排是 87 元哦!

在前面的例子裡,我們把資料都儲存在瀏覽器的 Cookie 中,這個方法稱為「Cookie-based session(以 Cookie 為基礎的 Session)」

在理解什麼是「Session Identifier」之前,我們可以先思考一下使用 Cookie 有什麼問題?為什麼會有 Session Identifier 的出現?

有一件很重要的事情要知道,那就是「Cookie 是可以被竄改的」:

1
2
3
4
瀏覽器:嗨,我要買咖啡,寄 10
Server:好,幸運餅乾借我,我儲存一下資料
Server:(把紙條塞到幸運餅乾裡)(set-Cookie: coffee=10)
Server:OK,歡迎下次再來。

這個時候,如果瀏覽器自己修改 Cookie 的值,就會變成這樣:

1
2
3
4
5
6
瀏覽器:(對幸運餅乾的紙條動手腳,改成 coffee = 20
瀏覽器:嗨,我來領我的咖啡
Server:好,幸運餅乾借我確認一下
Server:把幸運餅乾拆開(找到 coffee = 20
Server:你目前有 20 杯咖啡,你想要領幾杯呢?
瀏覽器:今晚我想來點...星巴克的巧克力可可碎片星冰樂不加巧克力。咳...我是說, 1 杯就好

為了解決 Cookie 被擅自竄改的問題,第一個會直覺想到的方法是:把 Cookie 中的資料做加密處理。

所以 Server 在設置 Cookie 的時候,可以先用一個加密的方式來產生資料,再把加密過後的資料存到 Cookie 裡:

1
2
3
4
5
瀏覽器:嗨,我要買咖啡,寄 10
Server:好,幸運餅乾借我,我儲存一下資料
Server:(把紙條塞到幸運餅乾裡)(set-Cookie: coffee=ED85B89167A84B631C10B046B5FB7FC0)
Server:OK,歡迎下次再來。
瀏覽器:GG

這時候如果瀏覽器想要竄改 Cookie 的值,就得先破解這套加密的演算法,才有辦法做修改。

這樣的做法確實解決了 Cookie 被擅自竄改的問題,但這依舊屬於 Cookie-based session。

這樣子做有什麼問題嗎?實際上是有的,因為 Cookie 能夠儲存的資料量是有限的(4KB),所以當要儲存在 Cookie 的資料越來越多時,很容易就會超出上限值。

為了解決這個問題,「Session Identifier」就誕生了。

它背後的原理是這樣子:

Server 現在不把資料儲存在瀏覽器的 Cookie 了,而是都儲存在 Server 這邊。至於 Cookie 則只會儲存一個用來辨識身分的識別碼,透過這個識別碼,Server 就可以在自己的記事本上找到對應的資料。

1
2
3
4
瀏覽器:嗨,我要買咖啡,寄 10
Server:好,幸運餅乾借我,我儲存一下資料
Server:(把紙條塞到幸運餅乾裡)(set-SessionId: A59Uhe7I94J330mN )
Server:(在自己的記事本上寫下:A59Uhe7I94J330mN : coffee=10

當下一次瀏覽器來領咖啡時:

1
2
3
4
5
瀏覽器:嗨,我來領我的咖啡
Server:好,幸運餅乾借我確認一下哦
Server:把幸運餅乾拆開(找到 A59Uhe7I94J330mN )
Server:打開自己的記事本做查閱(找到 A59Uhe7I94J330mN : coffee=10
Server:好的,你目前有 10 杯咖啡,你想要幾杯呢?

儲存在 Cookie 中的識別碼稱為「SessionID」。

這樣子就解決了 Cookie 大小限制的問題,因為不論有多少資料要儲存,cookie 唯一要儲存的資料都只有識別碼(SessionId)。

不過有一點要特別提醒的是:Server 只認 SessionId 不認人。也就是說,不管是誰,只要他的 Cookie 中的 SessionId 可以對應到 Server 中儲存的資訊,那他就可以取得相對應的資料。

總結

最後,試著問自己這些問題,看看自己有沒有真的理解:

  1. HTTP 的無狀態是什麼意思?
  2. Session 是用來做什麼的?
  3. 怎麼實作 session?
  4. Cookie-base Session 跟 Cookie 有什麼差異?
  5. Cookie-base Session 會有什麼問題,session Identifier 又是用來解決什麼問題?

答案都在內文裡了,如果忘記了就在去裡面找答案吧。

參考資料

MDN-Web Storage API
白話 Session 與 Cookie:從經營雜貨店開始

mentor-program-day01 談談 JS 中的 Closure(閉包)
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×