再好好聊一聊 HTTP 中的 Cookie細節(jié)
一、序
Hi,大家好,我是承香墨影!
HTTP 協(xié)議在網(wǎng)絡知識中占據(jù)了重要的地位,HTTP 協(xié)議最基礎的就是請求和響應的報文,而報文又是由報文頭(Header)和實體組成。大多數(shù) HTTP 協(xié)議的使用方式,都是依賴設置不同的 HTTP 請求/響應 的 Header 來實現(xiàn)的。
本系列《實用 HTTP》就拋開常規(guī)的 Header 講解式的表述方式,從實際問題出發(fā),來分析這些 HTTP 協(xié)議的使用方式,到底是為了解決什么問題?同時講解它是如何設計的和它實現(xiàn)原理。
HTTP 協(xié)議是一種無狀態(tài)的“松散協(xié)議”,它不會記錄不同請求的狀態(tài),并且因為它本身包含了兩端(客戶端和服務端),根據(jù)請求和響應來區(qū)分,它大部分的內(nèi)容都只是一個建議,其實雙邊是可以不遵守此建議的。
本身 HTTP 就是一個無狀態(tài)的協(xié)議,但是有時候我們又有需要增加狀態(tài)的需求,這個時候延伸出來了 Cookie,利用 Cookie 可以讓傳輸?shù)臅r候保持一些狀態(tài)信息。
本文就來講講 Cookie 的所有細節(jié)。
二、Cookie的使用
2.1 什么是 Cookie?
先明確一點,Cookie 就是為了解決 HTTP 協(xié)議無狀態(tài)的問題,接下來舉個例子說明。
早年間醫(yī)院對患者的病例還沒有在線建檔的時候,都需要患者在就醫(yī)之前,辦理一個病歷的小冊子,醫(yī)生會在病歷中寫上此次就醫(yī)的情況,什么時間、有什么表現(xiàn)的反映、診斷是什么病、開了一些什么藥等等。如果下次又生病了,有病歷的情況下,都會要求患者再把病歷帶上,這樣醫(yī)生就能通過病歷了解到之前的情況。
在 Cookie 的實現(xiàn)上,也是這樣的。
服務端(醫(yī)生)在收到客戶端(患者)請求的時候,將一些用戶標識信息加入到 Cookie (病例)中,隨著響應返回給客戶端,客戶端將 Cookie 中的信息存儲在本地,下次再請求此服務器的時候,再將 Cookie 中攜帶的數(shù)據(jù)原樣傳輸給服務端,此時服務端就能通過 Cookie 中的用戶標識,識別出這是之前請求過的某個用戶。
在這個例子中,服務端就是醫(yī)生的角色、客戶端是患者的角色、Cookie 就是病歷。
Netscape 官方文檔中的定義為:Cookie 是指在 HTTP 協(xié)議下,服務器或腳本可以維護客戶端計算機上信息的一種方式 。通俗地說,Cookie 是一種能夠讓網(wǎng)站 Web 服務器把少量數(shù)據(jù)儲存到客戶端的硬盤或內(nèi)存里,或是從客戶端的硬盤里讀取數(shù)據(jù)的一種技術。 Cookie 文件則是指在瀏覽某個網(wǎng)站時,由 Web 服務器的 CGI 腳本創(chuàng)建的存儲在瀏覽器客戶端計算機上的一個小文本文件。
2.2 一個完整的 Cookie 傳輸流程
HTTP 協(xié)議中的規(guī)則,都是通過在請求頭和響應頭中寫入輸入來實現(xiàn),Cookie 也是這樣的。
服務端通過 Set-Cookie 這個響應頭來向客戶端中寫入 Cookie 信息,而客戶端讀取 Set-Cookie 這個響應頭中的信息存儲起來,在下次請求的時候取出來,再通過 Cookie 這個請求頭,將 Cookie 的數(shù)據(jù)傳輸給服務端。
再看一個瀏覽器中,Cookie 使用的實例。
在響應頭(Response Header)中,使用 Set-Cookie 傳遞不同的 Cookie 數(shù)據(jù),多個數(shù)據(jù)可以分開成多個 Set-Cookie 頭。
在請求頭中(Request Header)中,使用 Cookie 這個請求頭傳遞 Cookie 數(shù)據(jù),不同的數(shù)據(jù)通過 ;分割。
三、Cookie 的細節(jié)
到這里,我想你應該弄清楚了 cookie 的整個執(zhí)行流程,接下來我們再來探究一些 cookie 的細節(jié)。
3.1 Cookie 的類型
cookie 其實都是存儲在客戶端,通常我們說 cookie 對應的客戶端,就是在說瀏覽器。
對于 cookie,我們可以簡單的將 cookie 分為兩類:
- 會話 cookie。
- 持久 cookie。
會話 cookie 是一種臨時的 cookie,用于存儲一些臨時的信息,存儲在內(nèi)存中,會話 cookie 在用戶退出瀏覽器的時候,會被清空刪除。而持久 cookie 的生存周期會更長久一些,被存儲在磁盤上,瀏覽器重啟后它們依然存在,但是他們會有一個過期的時間,只在此時間之后會被置為失效。
會話 cookie 和持久 cookie 之間唯一的區(qū)別就是它們的過期時間,只要是設置了過期時間的 cookie 就是持久 cookie,反之則是會話 cookie。
仔細看前面的流程圖中,有一個 domain 的字段是用于標識當前 Cookie 支持的域名的,而想要設置過期時間,可以使用 Expires 或者 Max-Age 參數(shù)進行設置,有點類似我們前面講 HTTP 緩存的參數(shù)。
3.2 Cookie 的配置參數(shù)
到現(xiàn)在我們已經(jīng)介紹了兩個 Cookie 配置的信息,Domain 和 Expires/Max-Age,分別用來配置域名和過期策略。
這些都很好理解,畢竟瀏覽器是開放的,它會訪問很多不同的網(wǎng)址,如果每個請求都將所有的 Cookie 信息都傳遞過去,基本上是不現(xiàn)實的。而這些配置參數(shù),就是對 Cookie 增加一些附加的設置,進行一些簡單的限制和過濾,在減少傳輸量的同時也保證了安全。
Domain 這個參數(shù)可以限制只在此域名下的請求,才傳遞該 Cookie,其他的不傳遞。
Cookie 其實還支持其他的一些參數(shù)配置,打開 Chrome 的調(diào)試模式,在 Application 中就可以看到當前頁面的 Cookie 信息。
下面以一篇微信文章頁面所存儲的 Cookie 為例。
這個表中,就是當前存儲的所有 Cookie 信息,而表頭,則是 Chrome 支持的 Cookie 信息。
下面我們分別來介紹它們。
- Name:Value :Cookie 存儲的數(shù)據(jù)就是一個 Key-Value 的鍵值對,所以這兩個參數(shù)沒什么爭議,就是數(shù)據(jù)的 Key 和 Value。
- Domain:Cookie 的域,限制請求頭傳輸?shù)挠颉?/li>
- Path:域中與 Cookie 相關的路徑前綴。
- Expires/Max-Age:過期時間或者超時間隔。
- http:此屬性為 True,表示只會在 HTTP 請求頭中攜帶此 Cookie 信息,而無法通過 document.cookie 來訪問此 Cookie。
- Secure:安全,是否只有在使用 SSL 連接時才發(fā)送這個 Cookie。
其實都很好理解,就不展開講解了。
3.3 Set-Cookie2 和 Cookie2
有些資料里會提到 Set-Cookie2 和 Cookie2 ,這些都是歷史遺留問題,當初想對 Cookie 再進行一些功能上的擴展,但并未得到廣泛的實施,現(xiàn)在已經(jīng)棄用了。
大家了解一下即可,有興趣可以參考 RFC 6265。
RFC 6265:
https://tools.ietf.org/html/rfc6265
3.4 瀏覽器對 Cookie 的限制
大部分時候我們聊到 Cookie 都在說的是服務器和瀏覽器進行通信時候,而不同的瀏覽器對 Cookie 存儲的限制是不一樣的。例如:單個域名可存儲的 Cookie 數(shù)量、Cookie 大小等。
我簡單找了一些資料,來說明不同瀏覽器對 Cookie 的支持情況。
這些數(shù)據(jù)我沒有驗證過,但是也能說明不同瀏覽器對 Cookie 的支持情況。在進行頁面 Cookie 操作的時候,應該盡量保證 Cookie 的個數(shù)小于 20 個,總大小小于 4KB,這是一個安全且保險的范圍。
四、Cookie的查缺補漏
4.1 Cookie 安全
前面配置 Cookie 參數(shù)的時候,有兩個參數(shù):http 和 secure 屬性,它們就在一定程度上保證了安全。
1. http 屬性
設置了 http 屬性,標識它是一個 “HttpOnly” 的,那么通過一些腳本程序(例如 JS的 document.cookie)將無法讀取到這個 Cookie 信息,它只會出現(xiàn)在請求的報文頭內(nèi)。
2. secure 屬性
secure 屬性強制該 Cookie 只有在 SSL 的環(huán)境下才會想服務器傳輸,相對也保證了傳輸?shù)陌踩?/p>
4.2 Cookie 不支持跨域
Cookie 本身是不支持跨域的,一定程度也保證了 Cookie 的安全,如果非要跨域其實作為前端基本上能做的很少,大部分都需要服務端的二次配合。
例如:nginx 反向代理、Jsonp、nodejs 的 superagent、iframe 等方法。
有興趣再單獨了解就好了。
五、Cookie 小結
HTTP 中的 Cookie 知識點,基本上都已經(jīng)講解清楚了,我們再次總結一下關鍵知識點。
1. Cookie 主要是為了解決 HTTP 協(xié)議無狀態(tài)的問題。
2. 服務端通過 Set-Cookie 響應頭來向客戶端設置 Cookie。
3. 客戶端通過 Cookie 請求頭向服務端發(fā)送之前存儲的 Cookie 數(shù)據(jù)。
4. Cookie 依據(jù)過期時間進行區(qū)分,將類型分為:臨時 Cookie 和 持久 Cookie。
5. Cookie 可以通過配置不同的參數(shù),進行限制,例如過期時間、支持的域名、是否安全(secure)等。
6. Cookie 不支持跨域,跨域還需要其他的方式繞開來實現(xiàn)。
7. Cookie 只能做到相對的安全,任何事情沒有絕對的安全。
參考:
Cookie 個數(shù)限制及大小:https://my.oschina.net/gaollg/blog/71299。
RFC 6265:https://tools.ietf.org/html/rfc6265
cookie 小結:http://www.cnblogs.com/xianyulaodi/p/6476991.html
【本文為51CTO專欄作者“張旸”的原創(chuàng)稿件,轉(zhuǎn)載請通過微信公眾號聯(lián)系作者獲取授權】