再好好聊聊 HTTP 裡的 Cookie | 實用 HTTP

承香墨影發表於2018-08-08

再好好聊聊 HTTP 裡的 Cookie | 實用 HTTP

題圖:by Juan Pablo Arenas

一、序

Hi,大家好,我是承香墨影!

HTTP 協議在網路知識中佔據了重要的地位,HTTP 協議最基礎的就是請求和響應的報文,而報文又是由報文頭(Header)和實體組成。大多數 HTTP 協議的使用方式,都是依賴設定不同的 HTTP 請求/響應 的 Header 來實現的。

本系列《實用 HTTP》就拋開常規的 Header 講解式的表述方式,從實際問題出發,來分析這些 HTTP 協議的使用方式,到底是為了解決什麼問題?同時講解它是如何設計的和它實現原理。

HTTP 協議是一種無狀態的“鬆散協議”,它不會記錄不同請求的狀態,並且因為它本身包含了兩端(客戶端和服務端),根據請求和響應來區分,它大部分的內容都只是一個建議,其實雙邊是可以不遵守此建議的。

“這裡寫了建議零售價 2 元...”

“哦,不接受建議!”

文字是本系列的第四篇,前三篇傳送門:

本身 HTTP 就是一個無狀態的協議,但是有時候我們又有需要增加狀態的需求,這個時候延伸出來了 Cookie,利用 Cookie 可以讓傳輸的時候保持一些狀態資訊。

本文就來講講 Cookie 的所有細節。

二、Cookie的使用

2.1 什麼是 Cookie?

先明確一點,Cookie 就是為了解決 HTTP 協議無狀態的問題,接下來舉個例子說明。

早年間醫院對患者的病例還沒有線上建檔的時候,都需要患者在就醫之前,辦理一個病歷的小冊子,醫生會在病歷中寫上此次就醫的情況,什麼時間、有什麼表現的反映、診斷是什麼病、開了一些什麼藥等等。如果下次又生病了,有病歷的情況下,都會要求患者再把病歷帶上,這樣醫生就能通過病歷瞭解到之前的情況。

在 Cookie 的實現上,也是這樣的。

服務端(醫生)在收到客戶端(患者)請求的時候,將一些使用者標識資訊加入到 Cookie (病例)中,隨著響應返回給客戶端,客戶端將 Cookie 中的資訊儲存在本地,下次再請求此伺服器的時候,再將 Cookie 中攜帶的資料原樣傳輸給服務端,此時服務端就能通過 Cookie 中的使用者標識,識別出這是之前請求過的某個使用者。

在這個例子中,服務端就是醫生的角色、客戶端是患者的角色、Cookie 就是病歷。

Netscape 官方文件中的定義為:Cookie 是指在 HTTP 協議下,伺服器或指令碼可以維護客戶端計算機上資訊的一種方式 。通俗地說,Cookie 是一種能夠讓網站 Web 伺服器把少量資料儲存到客戶端的硬碟或記憶體裡,或是從客戶端的硬碟裡讀取資料的一種技術。 Cookie 檔案則是指在瀏覽某個網站時,由 Web 伺服器的 CGI 指令碼建立的儲存在瀏覽器客戶端計算機上的一個小文字檔案。

2.2 一個完整的 Cookie 傳輸流程

HTTP 協議中的規則,都是通過在請求頭和響應頭中寫入輸入來實現,Cookie 也是這樣的。

服務端通過 Set-Cookie 這個響應頭來向客戶端中寫入 Cookie 資訊,而客戶端讀取 Set-Cookie 這個響應頭中的資訊儲存起來,在下次請求的時候取出來,再通過 Cookie 這個請求頭,將 Cookie 的資料傳輸給服務端。

再好好聊聊 HTTP 裡的 Cookie | 實用 HTTP

再看一個瀏覽器中,Cookie 使用的例項。

再好好聊聊 HTTP 裡的 Cookie | 實用 HTTP

在響應頭(Response Header)中,使用 Set-Cookie 傳遞不同的 Cookie 資料,多個資料可以分開成多個 Set-Cookie 頭。

在請求頭中(Request Header)中,使用 Cookie 這個請求頭傳遞 Cookie 資料,不同的資料通過 ;分割。

三、Cookie 的細節

到這裡,我想你應該弄清楚了 cookie 的整個執行流程,接下來我們再來探究一些 cookie 的細節。

3.1 Cookie 的型別

cookie 其實都是儲存在客戶端,通常我們說 cookie 對應的客戶端,就是在說瀏覽器。

對於 cookie,我們可以簡單的將 cookie 分為兩類:

  • 會話 cookie。
  • 持久 cookie。

會話 cookie 是一種臨時的 cookie,用於儲存一些臨時的資訊,儲存在記憶體中,會話 cookie 在使用者退出瀏覽器的時候,會被清空刪除。而持久 cookie 的生存週期會更長久一些,被儲存在磁碟上,瀏覽器重啟後它們依然存在,但是他們會有一個過期的時間,只在此時間之後會被置為失效。

會話 cookie 和持久 cookie 之間唯一的區別就是它們的過期時間,只要是設定了過期時間的 cookie 就是持久 cookie,反之則是會話 cookie。

仔細看前面的流程圖中,有一個 domain 的欄位是用於標識當前 Cookie 支援的域名的,而想要設定過期時間,可以使用 Expires 或者 Max-Age 引數進行設定,有點類似我們前面講 HTTP 快取的引數。

3.2 Cookie 的配置引數

到現在我們已經介紹了兩個 Cookie 配置的資訊,DomainExpires/Max-Age,分別用來配置域名和過期策略。

這些都很好理解,畢竟瀏覽器是開放的,它會訪問很多不同的網址,如果每個請求都將所有的 Cookie 資訊都傳遞過去,基本上是不現實的。而這些配置引數,就是對 Cookie 增加一些附加的設定,進行一些簡單的限制和過濾,在減少傳輸量的同時也保證了安全。

Domain 這個引數可以限制只在此域名下的請求,才傳遞該 Cookie,其他的不傳遞。

Cookie 其實還支援其他的一些引數配置,開啟 Chrome 的除錯模式,在 Application 中就可以看到當前頁面的 Cookie 資訊。

下面以一篇微信文章頁面所儲存的 Cookie 為例。

再好好聊聊 HTTP 裡的 Cookie | 實用 HTTP

這個表中,就是當前儲存的所有 Cookie 資訊,而表頭,則是 Chrome 支援的 Cookie 資訊。

下面我們分別來介紹它們。

  • Name:Value :Cookie 儲存的資料就是一個 Key-Value 的鍵值對,所以這兩個引數沒什麼爭議,就是資料的 Key 和 Value。
  • Domain:Cookie 的域,限制請求頭傳輸的域。
  • Path:域中與 Cookie 相關的路徑字首。
  • Expires/Max-Age:過期時間或者超時間隔。
  • http:此屬性為 True,表示只會在 HTTP 請求頭中攜帶此 Cookie 資訊,而無法通過 document.cookie 來訪問此 Cookie。
  • Secure:安全,是否只有在使用 SSL 連線時才傳送這個 Cookie。

其實都很好理解,就不展開講解了。

3.3 Set-Cookie2 和 Cookie2

有些資料裡會提到 Set-Cookie2Cookie2 ,這些都是歷史遺留問題,當初想對 Cookie 再進行一些功能上的擴充套件,但並未得到廣泛的實施,現在已經棄用了。

大家瞭解一下即可,有興趣可以參考 RFC 6265。

RFC 6265:

https://tools.ietf.org/html/rfc6265

3.4 瀏覽器對 Cookie 的限制

大部分時候我們聊到 Cookie 都在說的是伺服器和瀏覽器進行通訊時候,而不同的瀏覽器對 Cookie 儲存的限制是不一樣的。例如:單個域名可儲存的 Cookie 數量、Cookie 大小等。

我簡單找了一些資料,來說明不同瀏覽器對 Cookie 的支援情況。

再好好聊聊 HTTP 裡的 Cookie | 實用 HTTP

這些資料我沒有驗證過,但是也能說明不同瀏覽器對 Cookie 的支援情況。在進行頁面 Cookie 操作的時候,應該儘量保證 Cookie 的個數小於 20 個,總大小小於 4KB,這是一個安全且保險的範圍。

四、Cookie的查缺補漏

4.1 Cookie 安全

前面配置 Cookie 引數的時候,有兩個引數:http 和 secure 屬性,它們就在一定程度上保證了安全。

1. http 屬性

設定了 http 屬性,標識它是一個 “HttpOnly” 的,那麼通過一些指令碼程式(例如 JS的 document.cookie)將無法讀取到這個 Cookie 資訊,它只會出現在請求的報文頭內。

2. secure 屬性

secure 屬性強制該 Cookie 只有在 SSL 的環境下才會想伺服器傳輸,相對也保證了傳輸的安全。

4.2 Cookie 不支援跨域

Cookie 本身是不支援跨域的,一定程度也保證了 Cookie 的安全,如果非要跨域其實作為前端基本上能做的很少,大部分都需要服務端的二次配合。

例如:nginx 反向代理、Jsonp、nodejs 的 superagent、iframe 等方法。

有興趣再單獨瞭解就好了。

五、Cookie 小結

HTTP 中的 Cookie 知識點,基本上都已經講解清楚了,我們再次總結一下關鍵知識點。

1. Cookie 主要是為了解決 HTTP 協議無狀態的問題。

2. 服務端通過 Set-Cookie 響應頭來向客戶端設定 Cookie。

3. 客戶端通過 Cookie 請求頭向服務端傳送之前儲存的 Cookie 資料。

4. Cookie 依據過期時間進行區分,將型別分為:臨時 Cookie 和 持久 Cookie。

5. Cookie 可以通過配置不同的引數,進行限制,例如過期時間、支援的域名、是否安全(secure)等。

6. Cookie 不支援跨域,跨域還需要其他的方式繞開來實現。

7. Cookie 只能做到相對的安全,任何事情沒有絕對的安全。

參考:


聯機圓桌」?一年 50 個優質問題,上桌聯機學習。

公眾號後臺回覆成長『成長』,將會得到我準備的學習資料,也能回覆『加群』,一起學習進步;你還能回覆『提問』,向我發起提問。

推薦閱讀:

Android P 適配經驗 | 技術創業選擇清單 | HTTP傳輸編碼 | 什麼正在消耗你? | HTTP 內容編碼 | 圖解 HTTP 快取 | 輔助模式實戰 | Accessibility 輔助模式 | 小程式 Flex 佈局 | 好的 PR 讓你更靠譜 | 密碼管理之道

再好好聊聊 HTTP 裡的 Cookie | 實用 HTTP

相關文章