JavaScript Cookie

2018-07-24 11:52 更新

目錄

概述

Cookie 是服務(wù)器保存在瀏覽器的一小段文本信息,每個(gè) Cookie 的大小一般不能超過(guò)4KB。瀏覽器每次向服務(wù)器發(fā)出請(qǐng)求,就會(huì)自動(dòng)附上這段信息。

Cookie 保存以下幾方面的信息。

  • Cookie的名字
  • Cookie的值
  • 到期時(shí)間
  • 所屬域名(默認(rèn)是當(dāng)前域名)
  • 生效的路徑(默認(rèn)是當(dāng)前網(wǎng)址)

舉例來(lái)說(shuō),如果當(dāng)前URL是www.example.com,那么Cookie的路徑就是根目錄/。這意味著,這個(gè)Cookie對(duì)該域名的根路徑和它的所有子路徑都有效。如果路徑設(shè)為/forums,那么這個(gè)Cookie只有在訪問(wèn)www.example.com/forums及其子路徑時(shí)才有效。

瀏覽器可以設(shè)置不接受 Cookie,也可以設(shè)置不向服務(wù)器發(fā)送 Cookie。window.navigator.cookieEnabled屬性返回一個(gè)布爾值,表示瀏覽器是否打開(kāi) Cookie 功能。

document.cookie屬性返回當(dāng)前網(wǎng)頁(yè)的 Cookie。

// 讀取當(dāng)前網(wǎng)頁(yè)的所有cookie
var allCookies = document.cookie;

由于document.cookie返回的是分號(hào)分隔的所有Cookie,所以必須手動(dòng)還原,才能取出每一個(gè)Cookie的值。

var cookies = document.cookie.split(';');

for (var i = 0; i < cookies.length; i++) {
  // cookies[i] name=value形式的單個(gè)Cookie
}

document.cookie屬性是可寫(xiě)的,可以通過(guò)它為當(dāng)前網(wǎng)站添加Cookie。

document.cookie = 'fontSize=14';

Cookie的值必須寫(xiě)成key=value的形式。注意,等號(hào)兩邊不能有空格。另外,寫(xiě)入Cookie的時(shí)候,必須對(duì)分號(hào)、逗號(hào)和空格進(jìn)行轉(zhuǎn)義(它們都不允許作為Cookie的值),這可以用encodeURIComponent方法達(dá)到。

但是,document.cookie一次只能寫(xiě)入一個(gè)Cookie,而且寫(xiě)入并不是覆蓋,而是添加。

document.cookie = 'test1=hello';
document.cookie = 'test2=world';
document.cookie
// test1=hello;test2=world

document.cookie屬性讀寫(xiě)行為的差異(一次可以讀出全部Cookie,但是只能寫(xiě)入一個(gè)Cookie),與服務(wù)器與瀏覽器之間的Cookie通信格式有關(guān)。瀏覽器向服務(wù)器發(fā)送Cookie的時(shí)候,是一行將所有Cookie全部發(fā)送。

GET /sample_page.html HTTP/1.1
Host: www.example.org
Cookie: cookie_name1=cookie_value1; cookie_name2=cookie_value2
Accept: */*

上面的頭信息中,Cookie字段是瀏覽器向服務(wù)器發(fā)送的Cookie。

服務(wù)器告訴瀏覽器需要儲(chǔ)存Cookie的時(shí)候,則是分行指定。

HTTP/1.0 200 OK
Content-type: text/html
Set-Cookie: cookie_name1=cookie_value1
Set-Cookie: cookie_name2=cookie_value2; expires=Sun, 16 Jul 3567 06:23:41 GMT

上面的頭信息中,Set-Cookie字段是服務(wù)器寫(xiě)入瀏覽器的Cookie,一行一個(gè)。

如果仔細(xì)看瀏覽器向服務(wù)器發(fā)送的Cookie,就會(huì)意識(shí)到,Cookie協(xié)議存在問(wèn)題。對(duì)于服務(wù)器來(lái)說(shuō),有兩點(diǎn)是無(wú)法知道的。

  • Cookie的各種屬性,比如何時(shí)過(guò)期。
  • 哪個(gè)域名設(shè)置的Cookie,因?yàn)镃ookie可能是一級(jí)域名設(shè)的,也可能是任意一個(gè)二級(jí)域名設(shè)的。

除了Cookie本身的內(nèi)容,還有一些可選的屬性也是可以寫(xiě)入的,它們都必須以分號(hào)開(kāi)頭。

Set-Cookie: value[; expires=date][; domain=domain][; path=path][; secure]

上面的Set-Cookie字段,用分號(hào)分隔多個(gè)屬性。它們的含義如下。

(1)value屬性

value屬性是必需的,它是一個(gè)鍵值對(duì),用于指定Cookie的值。

(2)expires屬性

expires屬性用于指定Cookie過(guò)期時(shí)間。它的格式采用Date.toUTCString()的格式。

如果不設(shè)置該屬性,或者設(shè)為null,Cookie只在當(dāng)前會(huì)話(session)有效,瀏覽器窗口一旦關(guān)閉,當(dāng)前Session結(jié)束,該Cookie就會(huì)被刪除。

瀏覽器根據(jù)本地時(shí)間,決定Cookie是否過(guò)期,由于本地時(shí)間是不精確的,所以沒(méi)有辦法保證Cookie一定會(huì)在服務(wù)器指定的時(shí)間過(guò)期。

(3)domain屬性

domain屬性指定Cookie所在的域名,比如example.com.example.com(這種寫(xiě)法將對(duì)所有子域名生效)、subdomain.example.com。

如果未指定,默認(rèn)為設(shè)定該Cookie的域名。所指定的域名必須是當(dāng)前發(fā)送Cookie的域名的一部分,比如當(dāng)前訪問(wèn)的域名是example.com,就不能將其設(shè)為google.com。只有訪問(wèn)的域名匹配domain屬性,Cookie才會(huì)發(fā)送到服務(wù)器。

(4)path 屬性

path屬性用來(lái)指定路徑,必須是絕對(duì)路徑(比如/、/mydir),如果未指定,默認(rèn)為請(qǐng)求該 Cookie 的網(wǎng)頁(yè)路徑。

只有path屬性匹配向服務(wù)器發(fā)送的路徑,Cookie 才會(huì)發(fā)送。這里的匹配不是絕對(duì)匹配,而是從根路徑開(kāi)始,只要path屬性匹配發(fā)送路徑的一部分,就可以發(fā)送。比如,path屬性等于/blog,則發(fā)送路徑是/blog或者/blog/roll,Cookie都會(huì)發(fā)送。path屬性生效的前提是domain屬性匹配。

(5)secure 屬性

secure屬性用來(lái)指定Cookie只能在加密協(xié)議HTTPS下發(fā)送到服務(wù)器。

該屬性只是一個(gè)開(kāi)關(guān),不需要指定值。如果通信是HTTPS協(xié)議,該開(kāi)關(guān)自動(dòng)打開(kāi)。

(6)max-age

max-age屬性用來(lái)指定Cookie有效期,比如60 * 60 * 24 * 365(即一年31536e3秒)。

(7)HttpOnly

HttpOnly屬性用于設(shè)置該Cookie不能被JavaScript讀取,詳見(jiàn)下文的說(shuō)明。

以上屬性可以同時(shí)設(shè)置一個(gè)或多個(gè),也沒(méi)有次序的要求。如果服務(wù)器想改變一個(gè)早先設(shè)置的Cookie,必須同時(shí)滿足四個(gè)條件:Cookie的key、domain、pathsecure都匹配。也就是說(shuō),如果原始的Cookie是用如下的Set-Cookie設(shè)置的。

Set-Cookie: key1=value1; domain=example.com; path=/blog

改變上面這個(gè)cookie的值,就必須使用同樣的Set-Cookie。

Set-Cookie: key1=value2; domain=example.com; path=/blog

只要有一個(gè)屬性不同,就會(huì)生成一個(gè)全新的Cookie,而不是替換掉原來(lái)那個(gè)Cookie。

Set-Cookie: key1=value2; domain=example.com; path=/

上面的命令設(shè)置了一個(gè)全新的同名Cookie,但是path屬性不一樣。下一次訪問(wèn)example.com/blog的時(shí)候,瀏覽器將向服務(wù)器發(fā)送兩個(gè)同名的Cookie。

Cookie: key1=value1; key1=value2

上面代碼的兩個(gè)Cookie是同名的,匹配越精確的Cookie排在越前面。

瀏覽器設(shè)置這些屬性的寫(xiě)法如下。

document.cookie = 'fontSize=14; '
  + 'expires=' + someDate.toGMTString() + '; '
  + 'path=/subdirectory; '
  + 'domain=*.example.com';

另外,這些屬性只能用來(lái)設(shè)置Cookie。一旦設(shè)置完成,就沒(méi)有辦法讀取這些屬性的值。

刪除一個(gè)Cookie的簡(jiǎn)便方法,就是設(shè)置expires屬性等于0,或者等于一個(gè)過(guò)去的日期。

document.cookie = 'fontSize=;expires=Thu, 01-Jan-1970 00:00:01 GMT';

上面代碼中,名為fontSize的Cookie的值為空,過(guò)期時(shí)間設(shè)為1970年1月1月零點(diǎn),就等同于刪除了這個(gè)Cookie。

Cookie的限制

瀏覽器對(duì)Cookie數(shù)量的限制,規(guī)定不一樣。目前,F(xiàn)irefox是每個(gè)域名最多設(shè)置50個(gè)Cookie,而Safari和Chrome沒(méi)有域名數(shù)量的限制。

所有Cookie的累加長(zhǎng)度限制為4KB。超過(guò)這個(gè)長(zhǎng)度的Cookie,將被忽略,不會(huì)被設(shè)置。

由于Cookie可能存在數(shù)量限制,有時(shí)為了規(guī)避限制,可以將cookie設(shè)置成下面的形式。

name=a=b&c=d&e=f&g=h

上面代碼實(shí)際上是設(shè)置了一個(gè)Cookie,但是這個(gè)Cookie內(nèi)部使用&符號(hào),設(shè)置了多部分的內(nèi)容。因此,讀取這個(gè)Cookie的時(shí)候,就要自行解析,得到多個(gè)鍵值對(duì)。這樣就規(guī)避了cookie的數(shù)量限制。

同源政策

瀏覽器的同源政策規(guī)定,兩個(gè)網(wǎng)址只要域名相同和端口相同,就可以共享Cookie。

注意,這里不要求協(xié)議相同。也就是說(shuō),http://example.com設(shè)置的Cookie,可以被https://example.com讀取。

設(shè)置Cookie的時(shí)候,如果服務(wù)器加上了HttpOnly屬性,則這個(gè)Cookie無(wú)法被JavaScript讀?。?code class="highlighter-rouge">document.cookie不會(huì)返回這個(gè)Cookie的值),只用于向服務(wù)器發(fā)送。

Set-Cookie: key=value; HttpOnly

上面的這個(gè)Cookie將無(wú)法用JavaScript獲取。進(jìn)行AJAX操作時(shí),XMLHttpRequest對(duì)象也無(wú)法包括這個(gè)Cookie。這主要是為了防止XSS攻擊盜取Cookie。

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)