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