深刻淺出談Cookie

從經典的購物車提及

發現不少地方在介紹cookie的做用時,都喜歡使用購物車的例子,那咱們也不妨從這個例子開始提及。程序員

場景示例:有用戶a和b,都登錄了某個購物網站,此時若是兩個用戶都點擊了【查看購物車】按鈕,那麼此時服務器就同時收到了2個請求,請求的內容都是:「請告訴我個人購物車有什麼商品」。如今問題來了——服務器怎麼區分哪一個請求對應哪一個用戶呢web

其實這就是常常看到的那句話http協議是無狀態的。爲何說無狀態呢,由於http協議能夠當作一種簡單的應答模式:chrome

  • 客戶端發送一個請求,服務端返回相應的內容;
  • 客戶端(可能不是同一個客戶端了)又再發送一次請求,服務端(服務端仍是同一個)就再返回相應的內容,

那麼服務端知道兩次訪問的客戶端是否是同一個嗎?顯然是母雞呀!數據庫

http的無狀態

爲了解決這個問題,就要介紹今天的主角--Cookie。數組

cookie登場

能夠聯想一下生活中。咱們若是去一家生意火爆的火鍋店吃火鍋的場景(我突然有點想去吃個火鍋再回來寫了),這時若是有空座了,店員怎麼知道在門口等候的顧客應該輪到誰了呢?很簡單,在顧客等候以前,先發個號碼牌,後面根據號碼辨別身份。瀏覽器

?!!
靈光一閃緩存

看到這裏,是否是以爲有點餓了?啊呸,是否是以爲靈光乍現,上面說的問題和這個場景不是一模一樣嗎?因此,爲了可以讓會話能夠被識別,http中也引入了一個號碼牌——cookie的機制。(會話這個詞出現地有點突兀,簡單解釋下:a用戶登陸購物網站以後,接下來發生的一系列請求,都應該屬於服務端與a的會話安全

好了,原理大概說完了,那cookie具體怎麼實現呢?很簡單,放在http的頭部(headers)。在前一篇講狀態碼時,已經稍稍涉獵了一點http頭部的相關知識,簡單的來講http的頭部是一個js對象,裏面存放了一系列的鍵值對(key:value)用來表示各類信息,http的【請求】和【響應】都有頭部,而cookie機制的實現,則是藉助了其中的兩個字段:CookieSet-Cookie,整個運行流程能夠分紅如下步驟:服務器

  1. 客戶端發送一個http請求到服務端(我去告訴店員,我要吃火鍋了)
  2. 服務端響應該請求,而且在響應頭中包含了Set-Cookie(店員迴應我,而且給了我一張號碼牌,告訴我有任何須要都帶着號碼牌來申請)
  3. 客戶端發送請求,請求頭包含字段Cookie(我到店裏後,呼叫服務員來一份雪花牛肉,而且告訴他,個人號碼牌是6號
  4. 服務端根據請求中Cookie的內容響應。(服務員聽到後,根據個人號碼牌,給我給上了對應的菜)

在上述過程當中,可能同時也有其餘號碼牌的顧客在與服務員進行相似的交流過程,因爲服務員發給每一個顧客的號碼牌上的數字都是惟一的,因此沒必要懼怕弄混。cookie

cookie 的基本原理就是這麼簡單!
圖片描述

固然,在生活中吃完飯咱們就把號碼牌丟掉了,下次來吃從新取號就行;可是在http請求中,cookie能夠設置使用期限,好比說6個月後才過時。那麼客戶端接到這個內容後,就會把cookie緩存報本地的某個位置,以後若是訪問相同的站點,就能夠直接取出對應的cookie來使用。接下來咱們看個實際案例(又到了緊張刺激的舉例子環節,此次不只有例子,還有精美配圖,我以爲能夠點個贊再走~)。

首先,咱們打開chrome瀏覽器的【設置】-【內容設置】-【cookie】(也能夠在設置的頂部直接搜索),進入後能夠查看【全部的cookie和網站數據】,看看segmengt這一條數據。裏面一共有7個cookie,展開看詳細內容,能夠看到域名腳本可訪問到期時間等屬性,

圖片描述圖片描述

這些屬性後面再介紹,爲了看到整個流程,咱們先清除這個站點下的cookie,固然也能夠直接ctrl+shift+n打開一個隱身模式來直接測試。(隱身模式不會記錄cookie,咳咳,我固然也是爲了學習寫代碼才發現這個功能的!)

而後咱們打開segment站點,同時打開f12調試工具的network面板。能夠看到這個請求(能夠直接選doc類型查看,或者搜索框裏搜segment.com快速過濾),

響應頭的set-cookie
能夠看到這就對面前面說的第一個步驟:客戶端發送請求,服務端響應並提供set-cookie(也就是發放號碼牌的步驟)。

接下來咱們登陸這個網站而且再次請求這個站點。此時響應頭裏已經再也不有供set-cookie字段,由於cookie已經被緩存了(能夠去前面的設置裏再看看),而請求頭裏多了一個cookie字段。(這就是使用號碼牌的步驟了)。

接下來咱們把面板的請求類型切換到xhr,再點點頁面上的功能,好比收藏本文,或者給做者點贊、打賞(瘋狂暗示)等等。 能夠看到請求裏都帶上了cookie這個頭部。
請求頭的cookie

直到cookie過時,或者下次咱們又手動刪除這個站點cookie以前,原有的cookie均可以繼續使用。

set-cookiecookie

接下來咱們來講說set-cookie和cookie字段的具體內容。按照流程首先是來自服務端的set-cookie,直接copy一個前文的cookie下來,依此介紹:

set-cookie: test_cookie=CheckForPermission; expires=Mon, 25-Feb-2019 00:28:09 GMT; path=/; domain=.doubleclick.net
  1. 首先test_cookie=CheckForPermission,表示這個cookie的鍵值對,每一個cookie都會有本身的名稱和值
  2. expires=Mon, 25-Feb-2019 00:28:09 GMT表示cookie的有效期,這個值若是不指定,那麼默認值爲到瀏覽器關閉以前爲止
  3. path=/,將服務器上的某個文件目錄做爲cookie的使用對象(這麼抽象的解釋確定是書上說的),簡單的來講,是指定服務端有權限訪 問Cookie的路徑,例如/session/,表示只有/session/下才能夠訪問cookie,默認爲文檔所在的目錄。
  4. domain=.doubleclick.net,表示cookie所在的域。默認爲建立cookie的域。也就是請求地址,好比前面的segment.com
  5. secure,這個屬性前面沒有,表示只在https安全通訊時才發送cookie
  6. httpOnly,這個屬性前面也沒有,是用來限制使用腳本訪問cookie的,設置了這個值後,沒法在瀏覽器客戶端使用jsdocument.cookie讀取Cookie內容(頁面內部是能夠訪問的),這個功能能夠用來防止xss攻擊中利用js劫持cookie。

而cookie字段就簡單的多:一樣看一個實例:

cookie:HPSESSID=web2~a667ecfoft7u5e3umvgam3vs65; Hm_lvt_e23800c454aa573c0ccb16b52665ac26=1551052787; _ga=GA1.2.113018985.1551052787; _gid=GA1.2.1438865670.1551052787;

直接以鍵值對的形式發送須要的cookie,使用分號分割表示多個cookie。

使用cookie時,服務端會對發送來的cookie進行校驗,校驗的內容爲過時時間(expire)、域(domain)、路徑(path)、協議(是否secure),從而判斷cookie是否有效。若是服務端已經發出了一個cookie,以後想修改cookie的值怎麼辦呢?那就要建立一個同名的cookie進行覆蓋刪除。同名的要求是除了name和expire之外的屬性要和原來的cookie一致,不然會被看成不一樣的cookie保存。

cookie的優缺點

從前面的介紹咱們至少能夠看出cookie至少有如下幾個優勢:

  1. cookie的內容保存在客戶端,不佔用服務器資源
  2. 有效時間可配置,使用靈活
  3. 簡單的鍵值對結構,較爲輕量

固然缺點也顯而易見:

  1. cookie的長度通常會被限制在4k左右,超出部分會被丟棄
  2. 瀏覽器可存儲的cookie數量通常也是有數量限制的,ie八、Firefox限制爲每一個域名50個,chrome沒有限制,可是因爲規則1的存在,一個域名下cookie確定也不能很是多,不然內容就超過4k了
  3. cookie功能能夠被禁用,這就意味着基於cookie開發的功能要考慮如何應該這種狀況
  4. 不安全,容易被截取並篡改。
  5. 某些數據必須存在服務端,好比下面即將介紹的跨設備數據同步。

cookie的使用場景

大部分講cookie的文章都會提到這兩個例子,可是不多有具體的說明大概是怎麼實現的。這裏作下簡單的介紹。

自動登陸

假設某網站登陸時,提供了一個能夠勾選的【7天內免登陸】複選框,用戶勾選並正確登陸以後的流程大概是這樣的:

  1. 客戶端發送請求到服務端,請求信息裏包含用戶名密碼(固然通常是加密過的,可是我發現segment這裏登陸的時候竟然直接把密碼明文放在post的data裏,應該提個改進類的bug過去給他-_-!)
  2. 服務端接收請求後,建立一個id好比111,用於表示當前發送請求的客戶端,並存在服務端的某個位置,簡單點能夠認爲就存在一個名叫sessions的數組裏面吧。以後,把這個id放在響應的set-cookie裏面返回。例如:

    set-cookie:sessonId=111

同時,服務端設定數組sessions中的保存的111在7天后刪除

  1. 客戶端收到這個cookie以後保存,以後再次訪問的時候都帶上這個cookie,服務端接收到cookie裏附帶的sessionId=111後,去sessions數組查詢是否含有111,

    • 若是發現有,說明當前用戶能夠自動登陸,能夠直接跳轉到登陸以後的頁面
    • 若是不存在(已經被自動刪除了),那麼說明要從新登陸

(其實在上面已經悄咪咪的說了一丟丟session的內容,可是本着每次着重說明一個知識點、儘可能剝離無關內容的原則,依然不在本文插入session的相關知識)

未登陸時的購物車

本文已經屢次提到購物車了,可是細心的朋友能夠看到,這裏的前面添加了「未登陸」,那登陸時候爲何不用呢?由於咱們前面比較優缺點的時候,有提到cookie畢竟只能存儲在發送請求的那個客戶端設備,而電商網站通常是容許多終端登陸的(x寶,x貓,x夕夕等),若是使用cookie來保存登陸後的購物車內容,那更換設備的時候就沒法查到了,因此登陸狀態下的購物車通常是存到數據庫中的,只在離線的時候使用cookie的方式來處理比較合適。

核心思路:

  1. 首先初次進入頁面時,客戶端發送get請求,服務端在響應的set-cookie返回給客戶端一個商品列表
  2. 用戶點擊【將某商品添加到購物車】,客戶端發送請求攜帶cookie發送請求,而且在請求體中攜帶商品id
  3. 服務端接受到請求後,從請求頭的cookie中取出商品列表,從請求體中取出本次商品id,而後查找商品列表是否包含該商品id,若是包含,那對應商品id增長;若是不存在,則從數據庫查找該商品,並添加該商品信息和數量,並更新到cookie中

如何讀寫cookie

js讀寫cookie的方法處處都有,隨便搜索下應該就能找到,本文仍是着重於說明cookie的原理,就不在此贅述了。
圖片描述

小結

本文對cookie的原理和應用場景進行了說明,依然延續以往的「一篇文章只說一件事」的習慣(程序員的事,怎麼能叫偷懶呢,這叫模塊化封裝)。但願能對看完的同窗有所幫助(就算是隻收穫了表情包也是極好的)。順便說一下,前一篇文章彷佛效果不錯,騙到了不少收藏和點贊,很是開心(再次瘋狂暗示


慣例:若是內容有錯誤的地方歡迎指出(以爲看着不理解不舒服想吐槽也徹底沒問題);若是有幫助,歡迎點贊和收藏,轉載請徵得贊成後著明出處,若是有問題也歡迎私信交流,主頁有郵箱地址

相關文章
相關標籤/搜索