Cookie

概述

Cookie 是服务器保存在浏览器的一小段文本信息,每个 Cookie 的大小一般不能超过4KB。浏览器每次向服务器发出请求,就会自动附上这段信息。

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

  • Cookie 的名字
  • Cookie 的值
  • 到期时间
  • 所属域名(默认是当前域名)
  • 生效的路径(默认是当前网址)

举例来说,如果当前URL是[www.example.com](http://www.example.com/),那么Cookie的路径就是根目录/。这意味着,这个Cookie对该域名的根路径和它的所有子路径都有效。如果路径设为/forums,那么这个Cookie只有在访问[www.example.com/forums](http://www.example.com/forums)及其子路径时才有效。

浏览器可以设置不接受 Cookie,也可以设置不向服务器发送 Cookie。window.navigator.cookieEnabled属性返回一个布尔值,表示浏览器是否打开 Cookie 功能。

document.cookie属性返回当前网页的 Cookie。

// 读取当前网页的所有cookie
var allCookies = document.cookie;

由于document.cookie返回的是分号分隔的所有 Cookie,所以必须手动还原,才能取出每一个 Cookie 的值。

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

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

document.cookie属性是可写的,可以通过它为当前网站添加 Cookie。

document.cookie = 'fontSize=14';

Cookie 的值必须写成key=value的形式。注意,等号两边不能有空格。另外,写入 Cookie 的时候,必须对分号、逗号和空格进行转义(它们都不允许作为 Cookie 的值),这可以用encodeURIComponent方法达到。

但是,document.cookie一次只能写入一个 Cookie,而且写入并不是覆盖,而是添加。

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

document.cookie属性读写行为的差异(一次可以读出全部 Cookie,但是只能写入一个 Cookie),与服务器与浏览器之间的 Cookie 通信格式有关。浏览器向服务器发送 Cookie 的时候,是使用一行将所有 Cookie 全部发送。

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

上面的头信息中,Cookie字段是浏览器向服务器发送的 Cookie。

服务器告诉浏览器需要储存 Cookie 的时候,则是分行指定。

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字段是服务器写入浏览器的 Cookie,一行一个。

如果仔细看浏览器向服务器发送的 Cookie,就会意识到,Cookie 协议存在问题。对于服务器来说,有两点是无法知道的。

  • Cookie 的各种属性,比如何时过期。
  • 哪个域名设置的 Cookie,因为 Cookie 可能是一级域名设的,也可能是任意一个二级域名设的。

Cookie 的属性

服务器向浏览器发送 Cookie 的时候,除了 Cookie 本身的内容,还有一些可选的属性也是可以写入的,它们都必须以分号开头。

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

上面的Set-Cookie字段,用分号分隔多个属性。它们的含义如下。

(1)value 属性

value属性是必需的,它是一个键值对,用于指定Cookie的值。

(2)expires 属性

expires属性用于指定 Cookie 过期时间。它的格式采用Date.toUTCString()的格式。

如果不设置该属性,或者设为null,Cookie只在当前会话(session)有效,浏览器窗口一旦关闭,当前 Session 结束,该 Cookie 就会被删除。

浏览器根据本地时间,决定 Cookie 是否过期,由于本地时间是不精确的,所以没有办法保证 Cookie 一定会在服务器指定的时间过期。

(3)domain属性

domain属性指定 Cookie 所在的域名,比如[example.com](http://example.com/).[example.com](http://example.com/)(这种写法将对所有子域名生效)、[subdomain.example.com](http://subdomain.example.com/)

如果未指定,默认为设定该Cookie的域名。所指定的域名必须是当前发送Cookie的域名的一部分,比如当前访问的域名是[example.com](http://example.com/),就不能将其设为[google.com](http://google.com/)。只有访问的域名匹配 domain 属性,Cookie 才会发送到服务器。

(4)path 属性

path属性用来指定路径,必须是绝对路径(比如//mydir),如果未指定,默认为请求该 Cookie 的网页路径。

只有path属性匹配向服务器发送的路径,Cookie 才会发送。这里的匹配不是绝对匹配,而是从根路径开始,只要path属性匹配发送路径的一部分,就可以发送。比如,path属性等于/blog,则发送路径是/blog或者/blog/roll,Cookie都会发送。path属性生效的前提是domain属性匹配。

(5)secure 属性

secure属性用来指定Cookie只能在加密协议HTTPS下发送到服务器。

该属性只是一个开关,不需要指定值。如果通信是HTTPS协议,该开关自动打开。

(6)max-age

max-age属性用来指定Cookie有效期,比如60 * 60 * 24 * 365(即一年31536e3秒)。

(7)HttpOnly

HttpOnly属性用于设置该Cookie不能被JavaScript读取,详见下文的说明。

以上属性可以同时设置一个或多个,也没有次序的要求。如果服务器想改变一个早先设置的Cookie,必须同时满足四个条件:Cookie的keydomainpathsecure都匹配。也就是说,如果原始的Cookie是用如下的Set-Cookie设置的。

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

改变上面这个 Cookie 的值,就必须使用同样的Set-Cookie

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

只要有一个属性不同,就会生成一个全新的 Cookie,而不是替换掉原来那个 Cookie。

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

上面的命令设置了一个全新的同名 Cookie,但是path属性不一样。下一次访问[example.com/blog](http://example.com/blog)的时候,浏览器将向服务器发送两个同名的 Cookie。

Cookie: key1=value1; key1=value2

上面代码的两个 Cookie 是同名的,匹配越精确的Cookie排在越前面。

浏览器设置这些属性的写法如下。

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

另外,这些属性只能用来设置 Cookie。一旦设置完成,就没有办法读取这些属性的值。

删除一个 Cookie 的唯一方法是设置其expires为一个过去的日期。

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

上面代码中,名为fontSize的 Cookie 的值为空,过期时间设为1970年1月1月零点,就等同于删除了这个 Cookie。

Cookie 的限制

浏览器对 Cookie 数量的限制,规定不一样。目前,Firefox 是每个域名最多设置50个 Cookie,而 Safari 和 Chrome 没有域名数量的限制。

所有 Cookie 的累加长度限制为4KB。超过这个长度的 Cookie,将被忽略,不会被设置。

由于 Cookie 可能存在数量限制,有时为了规避限制,可以将 Cookie 设置成下面的形式。

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

上面代码实际上是设置了一个 Cookie,但是这个 Cookie 内部使用&符号,设置了多部分的内容。因此,读取这个 Cookie 的时候,就要自行解析,得到多个键值对。这样就规避了 Cookie 的数量限制。

同源政策

浏览器的同源政策规定,两个网址只要域名相同和端口相同,就可以共享 Cookie。

注意,这里不要求协议相同。也就是说,[http://example.com](http://example.com/)设置的Cookie,可以被[https://example.com](https://example.com/)读取。

Http-Only Cookie

设置 Cookie 的时候,如果服务器加上了HttpOnly属性,则这个 Cookie 无法被 JavaScript 读取(即document.cookie不会返回这个Cookie的值),只用于向服务器发送。

Set-Cookie: key=value; HttpOnly

上面的这个 Cookie 将无法用 JavaScript 获取。进行 AJAX 操作时,XMLHttpRequest对象也无法包括这个 Cookie。这主要是为了防止 XSS 攻击盗取 Cookie。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,864评论 6 494
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,175评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,401评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,170评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,276评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,364评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,401评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,179评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,604评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,902评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,070评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,751评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,380评论 3 319
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,077评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,312评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,924评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,957评论 2 351

推荐阅读更多精彩内容