Cookie,document.cookie

176 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第12天,点击查看活动详情

Cookie 是直接存储在浏览器中的一小串数据。它们是 HTTP 协议的一部分,由 RFC 6265 规范定义。

Cookie 通常是由 Web 服务器使用响应 Set-Cookie HTTP-header 设置的。然后浏览器使用 Cookie HTTP-header 将它们自动添加到(几乎)每个对相同域的请求中。

最常见的用处之一就是身份验证:

  1. 登录后,服务器在响应中使用 Set-Cookie HTTP-header 来设置具有唯一“会话标识符(session identifier)”的 cookie。
  2. 下次当请求被发送到同一个域时,浏览器会使用 Cookie HTTP-header 通过网络发送 cookie。
  3. 所以服务器知道是谁发起了请求。

我们还可以使用 document.cookie 属性从浏览器访问 cookie。

关于 cookie 及其选项,有很多棘手的事情。在本章中,我们将详细介绍它们。

从 document.cookie 中读取

你的浏览器是否存储了本网站的任何 cookie?让我们来看看:

// 在 javascript.info,我们使用谷歌分析来进行统计,
// 所以应该存在一些 cookie
alert( document.cookie ); // cookie1=value1; cookie2=value2;...

document.cookie 的值由 name=value 对组成,以 ; 分隔。每一个都是独立的 cookie。

为了找到一个特定的 cookie,我们可以以 ; 作为分隔,将 document.cookie 分开,然后找到对应的名字。我们可以使用正则表达式或者数组函数来实现。

我们把这个留给读者当作练习。此外,在本章的最后,你可以找到一些操作 cookie 的辅助函数。

写入 document.cookie

我们可以写入 document.cookie。但这不是一个数据属性,它是一个 访问器(getter/setter)。对其的赋值操作会被特殊处理。

对 document.cookie 的写入操作只会更新其中提到的 cookie,而不会涉及其他 cookie。

例如,此调用设置了一个名称为 user 且值为 John 的 cookie:

document.cookie = "user=John"; // 只会更新名称为 user 的 cookie
alert(document.cookie); // 展示所有 cookie

如果你运行了上面这段代码,你会看到多个 cookie。这是因为 document.cookie= 操作不是重写整所有 cookie。它只设置代码中提到的 cookie user

从技术上讲,cookie 的名称和值可以是任何字符。为了保持有效的格式,它们应该使用内建的 encodeURIComponent 函数对其进行转义:

// 特殊字符(空格),需要编码
let name = "my name";
let value = "John Smith"

// 将 cookie 编码为 my%20name=John%20Smith
document.cookie = encodeURIComponent(name) + '=' + encodeURIComponent(value);

alert(document.cookie); // ...; my%20name=John%20Smith

限制

存在一些限制:

  • encodeURIComponent 编码后的 name=value 对,大小不能超过 4KB。因此,我们不能在一个 cookie 中保存大的东西。
  • 每个域的 cookie 总数不得超过 20+ 左右,具体限制取决于浏览器。

Cookie 有几个选项,其中很多都很重要,应该设置它。

选项被列在 key=value 之后,以 ; 分隔,像这样:

document.cookie = "user=John; path=/; expires=Tue, 19 Jan 2038 03:14:07 GMT"

path

  • path=/mypath

url 路径前缀必须是绝对路径。它使得该路径下的页面可以访问该 cookie。默认为当前路径。

如果一个 cookie 带有 path=/admin 设置,那么该 cookie 在 /admin 和 /admin/something 下都是可见的,但是在 /home 或 /adminpage 下不可见。

通常,我们应该将 path 设置为根目录:path=/,以使 cookie 对此网站的所有页面可见。

domain

  • domain=site.com

domain 控制了可访问 cookie 的域。但是在实际中,有一些限制。我们无法设置任何域。

无法从另一个二级域访问 cookie,因此 other.com 永远不会收到在 site.com 设置的 cookie。

这是一项安全限制,为了允许我们将敏感数据存储在应该仅在一个站点上可用的 cookie 中。

默认情况下,cookie 只有在设置的域下才能被访问到。

请注意,默认情况下,cookie 也不会共享给子域,例如 forum.site.com

// 如果我们在 site.com 网站上设置了 cookie……
document.cookie = "user=John"

// ……在 forum.site.com 域下我们无法访问它
alert(document.cookie); // 没有 user

……但这是可以设置的。如果我们想允许像 forum.site.com 这样的子域在 site.com 上设置 cookie,也是可以实现的。

为此,当在 site.com 设置 cookie 时,我们应该明确地将 domain 选项设置为根域:domain=site.com。那么,所有子域都可以访问到这样的 cookie。

例如:

// 在 site.com
// 使 cookie 可以被在任何子域 *.site.com 访问:
document.cookie = "user=John; domain=site.com"

// 之后

// 在 forum.site.com
alert(document.cookie); // 有 cookie user=John

出于历史原因,domain=.site.comsite.com 前面有一个点符号)也以相同的方式工作,允许从子域访问 cookie。这是一个旧的表示方式,如果我们需要支持非常旧的浏览器,那么应该使用它。

总结一下,通过 domain 选项的设置,可以实现允许在子域访问 cookie。