diff --git a/6-data-storage/01-cookie/article.md b/6-data-storage/01-cookie/article.md index 438bda7eb5..4a87452c99 100644 --- a/6-data-storage/01-cookie/article.md +++ b/6-data-storage/01-cookie/article.md @@ -1,80 +1,80 @@ -# Cookies, document.cookie +# Cookie,document.cookie -cookies 是直接保存在浏览器上的小数据串。它们是 HTTP 协议的一部分,由 [RFC 6265](https://tools.ietf.org/html/rfc6265) 规范定义。 +Cookie 是直接存储在浏览器中的一小串数据。它们是 HTTP 协议的一部分,由 [RFC 6265](https://tools.ietf.org/html/rfc6265) 规范定义。 -大多数情况下,cookies 是由 web 服务器设置的。然后它们会自动添加到相同域名下的每次请求中。 +Cookie 通常是由网络服务器使用响应 `Set-Cookie` HTTP-header 设置的。然后浏览器使用 `Cookie` HTTP-header 将它们自动添加到(几乎)每个对相同域的请求中。 -最常见的用处之一是身份验证: +最常见的用处之一就是身份验证: -1. 登录后,服务端通过 `Set-Cookie` 在响应的 HTTP-header 中设置了一个带有 "会话标识符" 的 cookie。 -2. 下次如果相同域名发起了请求,浏览器会发送带有 `Cookie` 的 HTTP-header。 -3. 所以服务端知道是谁发起了请求。 +1. 登录后,服务器在响应中使用 `Set-Cookie` HTTP-header 来设置具有唯一“会话标识符”的 cookie。 +2. 下次如果请求是由相同域发起的,浏览器会使用 `Cookie` HTTP-header 通过网络发送 cookie。 +3. 所以服务器知道是谁发起了请求。 -我们还可以使用 `document.cookie` 属性在浏览器上访问 cookies。 +我们还可以使用 `document.cookie` 属性从浏览器访问 cookie。 -有关 cookies 和它们的选项有很多棘手的事情。在本章节中,我们将会详细介绍。 +关于 cookie 及其选项,有很多棘手的事情。在本章中,我们将详细介绍它们。 ## 从 document.cookie 中读取 ```online -你在这个网站上有 cookies 吗?让我们来看看: +你的浏览器是否存储了本网站的任何 cookie?让我们来看看: ``` ```offline -假设你在网站上可以看到 cookies,像这样: +假设你在一个网站上,则可以看到来自该网站的 cookie,像这样: ``` ```js run -// 在 javascript.info,我们使用谷歌分析来统计, -// 所以应该存在一些 cookies +// 在 javascript.info,我们使用谷歌分析来进行统计, +// 所以应该存在一些 cookie alert( document.cookie ); // cookie1=value1; cookie2=value2;... ``` -`document.cookie` 的值由一个个 `name=value` 组成,以 `; ` 相隔。每一个都是独立的 cookie。 +`document.cookie` 的值由 `name=value` 对组成,以 `; ` 分隔。每一个都是独立的 cookie。 -为了找到一个特定的 cookie,我们可以通过 `; ` 截取 `document.cookie`,然后找到合适的名字。我们可以使用正则表达式或者数组的方法来实现。 +为了找到一个特定的 cookie,我们可以以 `; ` 作为分隔,将 `document.cookie` 分开,然后找到对应的名字。我们可以使用正则表达式或者数组函数来实现。 -我们把这个留给读者当作练习。此外,在本章节的结尾,你可以找到一些操作 cookies 的辅助函数。 +我们把这个留给读者当作练习。此外,在本章的最后,你可以找到一些操作 cookie 的辅助函数。 ## 写入 document.cookie -我们可以写入 `document.cookie`。但是这不是一个数据属性,它是一个访问者(getter/setter)。赋值操作会被特殊处理。 +我们可以写入 `document.cookie`。但这不是一个数据属性,它是一个访问器(getter/setter)。对其的赋值操作会被特殊处理。 -**浏览器的 `document.cookie` 写入操作只会更新已存在的 cookies,而不会影响其他 cookies。** +**对 `document.cookie` 的写入操作只会更新其中提到的 cookie,而不会涉及其他 cookie。** -例如,这里设置了一个名称为 `user` 和值为 `John` 的 cookie: +例如,此调用设置了一个名称为 `user` 且值为 `John` 的 cookie: ```js run document.cookie = "user=John"; // 只会更新名称为 user 的 cookie -alert(document.cookie); // 展示所有 cookies +alert(document.cookie); // 展示所有 cookie ``` -如果你运行了代码,你很可能会看到多个 cookies。这是因为 `document.cookie=` 操作不是重写整个 cookies。它只设置代码中提到的 cookie `user`。 +如果你运行了上面这段代码,你会看到多个 cookie。这是因为 `document.cookie=` 操作不是重写整所有 cookie。它只设置代码中提到的 cookie `user`。 -从技术层面看,cookie 的名称和值能是任何字符,为了保持格式有效,它们应该使用 `encodeURIComponent` 内置方法来编码一下: +从技术上讲,cookie 的名称和值可以是任何字符,为了保持有效的格式,它们应该使用内建的 `encodeURIComponent` 函数对其进行转义: ```js run -// 特殊字符(空白符),需要编码 +// 特殊字符(空格),需要编码 let name = "my name"; let value = "John Smith" -// 编码后变成 my%20name=John%20Smith +// 将 cookie 编码为 my%20name=John%20Smith document.cookie = encodeURIComponent(name) + '=' + encodeURIComponent(value); alert(document.cookie); // ...; my%20name=John%20Smith ``` -```warn header="局限性" -存在一些局限性: -- `encodeURIComponent` 编码后的 `name=value` 对,大小不能超过 4kb。所以我们不能在一个 cookie 中保存大数据。 -- 每个域名下所有 cookies 的总数限制在 20 几个,实际的限制数量取决于浏览器。 +```warn header="限制" +存在一些限制: +- `encodeURIComponent` 编码后的 `name=value` 对,大小不能超过 4kb。因此,我们不能在一个 cookie 中保存大的东西。 +- 每个域的 cookie 总数不得超过 20+ 左右,具体限制取决于浏览器。 ``` -cookies 有好几个选项,很多选项都很重要并且应该设置它。 +Cookie 有几个选项,其中很多都很重要,应该设置它。 -选项列在 `key=value` 后面,使用 `;` 间隔,像这样: +选项被列在 `key=value` 之后,以 `;` 分隔,像这样: ```js run document.cookie = "user=John; path=/; expires=Tue, 19 Jan 2038 03:14:07 GMT" @@ -84,21 +84,21 @@ document.cookie = "user=John; path=/; expires=Tue, 19 Jan 2038 03:14:07 GMT" - **`path=/mypath`** -可访问到 cookie 的 url 路径前缀。必须是绝对路径。默认值为当前路径。 +url 路径前缀,该路径下的页面可以访问该 cookie。必须是绝对路径。默认为当前路径。 -如果一个 cookie 设置了 `path=/admin`,那么在 `/admin` 和 `/admin/something` 下都是可见的,但是在 `/home` 或 `/adminpage` 下不可见。 +如果一个 cookie 带有 `path=/admin` 设置,那么该 cookie 在 `/admin` 和 `/admin/something` 下都是可见的,但是在 `/home` 或 `/adminpage` 下不可见。 -通常,我们设置 `path=/` 来允许网站下所有页面访问 cookie。 +通常,我们应该将 `path` 设置为根目录:`path=/`,以使 cookie 对此网站的所有页面可见。 ## domain - **`domain=site.com`** -可访问到 cookie 的域名。但是在实践中,存在局限性。我们不能设置任何域名。 +可访问 cookie 的域。但是在实际中,有一些限制。我们无法设置任何域。 -默认情况下,cookie 只能在设置的域名下才能访问到。所以,如果 cookie 设置在 `site.com` 下,我们不能在任何其他域名下(`other.com`)访问它。 +默认情况下,cookie 只有在设置的域下才能被访问到。所以,如果 cookie 设置在 `site.com` 下,我们在 `other.com` 下就无法获取它。 -……但是棘手的是,我们在子域名下同样不能获取到 cookie(`forum.site.com`)! +……但是棘手的是,我们在子域 `forum.site.com` 下也无法获取它! ```js // 在 site.com @@ -108,170 +108,170 @@ document.cookie = "user=John" alert(document.cookie); // 没有 user ``` -**让 cookie 在另外一个二级域名下可以访问到是没有办法的,所以其他域名 `other.com` 将不会接收到设置在 `site.com` 的 cookie。** +**无法使 cookie 可以被从另一个二级域访问,因此,`other.com` 将永远不会收到设置在 `site.com` 的 cookie。** -这是一个安全限制,为了允许我们可以在 cookie 中保存敏感信息。 +这是一项安全限制,为了允许我们可以将敏感信息保存在 cookie 中。 -……但是如果我们想要批准像 `forum.site.com` 这样的子域名访问,这是可以做到的。我们应该明确设置 `domain` 选项为根域名:`domain=site.com`: +……但是,如果我们想要批准像 `forum.site.com` 这样的子域访问 cookie,这是可以做到的。当我们设置一个在 `site.com` 的 cookie 时,我们应该将 `domain` 选项显式地设置为根域:`domain=site.com`: ```js -// 在 site.com 中 -// 使 cookie 在其任何子域名下可以访问: +// 在 site.com +// 使 cookie 可以被在任何子域 *.site.com 访问: document.cookie = "user=John; domain=site.com" // 之后 // 在 forum.site.com -alert(document.cookie); // 也存在 user +alert(document.cookie); // 有 cookie user=John ``` -因为历史原因,`domain=.site.com`(以点开头)也可以正常使用,最好添加点来支持老版本的浏览器。 +出于历史原因,`domain=.site.com`(`site.com` 前面有一个点符号)也以相同的方式工作,允许从子域访问 cookie。这是一个旧的表示法,如果我们需要支持非常旧的浏览器,则应该使用它。 -所以,`domain` 选项允许子域名访问 cookie。 +所以,`domain` 选项允许设置一个可以在子域访问的 cookie。 -## expires, max-age +## expires,max-age -默认情况下,如果一个 cookie 没有设置这两个参数中的任何一个,那么在浏览器关闭后,它就会消失。此类 cookies 被称为 "session cookies”。 +默认情况下,如果一个 cookie 没有设置这两个参数中的任何一个,那么在关闭浏览器之后,它就会消失。此类 cookie 被称为 "session cookie”。 -为了让 cookies 在浏览器关闭后仍然存在,我们可以设置 `expires` 或 `max-age` 其中一个选项。 +为了让 cookie 在浏览器关闭后仍然存在,我们可以设置 `expires` 或 `max-age` 选项中的一个。 - **`expires=Tue, 19 Jan 2038 03:14:07 GMT`** -cookie 过期日期,当到了过期时间浏览器会自动删除它。 +cookie 的到期日期,那时浏览器会自动删除它。 -日期必须是这种格式,GMT 时区。我们可以使用 `date.toUTCString` 方法得到。举个例子,我们可以设置 cookie 在 1 天后过期。 +日期必须完全采用 GMT 时区的这种格式。我们可以使用 `date.toUTCString` 来获取它。例如,我们可以将 cookie 设置为 1 天后过期。 ```js -// 在当前时间上加 1 天 +// 当前时间 +1 天 let date = new Date(Date.now() + 86400e3); date = date.toUTCString(); document.cookie = "user=John; expires=" + date; ``` -如果我们设置 `expires` 为已经过去的时间,cookie 会被删除。 +如果我们将 `expires` 设置为过去的时间,则 cookie 会被删除。 - **`max-age=3600`** -一个可以替代 `expires` 的选项,具体说明 cookie 的过期时间距离当前时间的秒数。 +`expires` 的替代选项,具指明 cookie 的过期时间距离当前时间的秒数。 -如果是 0 或者负数,cookie 会被删除: +如果为 0 或负数,则 cookie 会被删除: ```js -// 1 小时后 cookie 会失效 +// cookie 会在一小时后失效 document.cookie = "user=John; max-age=3600"; -// 删除 cookie (让 cookie 马上过期) +// 删除 cookie(让它立即过期) document.cookie = "user=John; max-age=0"; -``` +``` ## secure - **`secure`** -cookie 应仅在 HTTPS 环境下传输。 +Cookie 应只能被通过 HTTPS 传输。 -**默认情况下,如果我们在 `http://site.com` 设置了 cookie,然后 cookie 在 `https://site.com` 中也会出现,反之亦然。** +**默认情况下,如果我们在 `http://site.com` 上设置了 cookie,那么该 cookie 也会出现在 `https://site.com` 上,反之亦然。** -也就是说,cookies 是基于域名的,它们不是通过协议来区分的。 +也就是说,cookie 是基于域的,它们不区分协议。 -有了这个选项,如果一个 cookie 通过 `https://site.com` 设置,然后它不会在相同域名的 HTTP 环境下出现,例如 `http://site.com`。所以,如果一个 cookie 存有敏感内容,不应该在不安全的 HTTP 环境下发送,此时这个选项就派上用场了。 +使用此选项,如果一个 cookie 是通过 `https://site.com` 设置的,那么它不会在相同域的 HTTP 环境下出现,例如 `http://site.com`。所以,如果一个 cookie 包含绝不应该通过未加密的 HTTP 协议发送的敏感内容,那么就应该设置这个选项。 ```js // 假设我们现在在 HTTPS 环境下 -// 设置 cookie secure(只在 HTTPS 环境下传输) +// 设置 cookie secure(只在 HTTPS 环境下可访问) document.cookie = "user=John; secure"; ``` ## samesite -这是另外一个关于安全的选项,为了防止 XSRF(跨站点请求伪造)攻击。 +这是另外一个关于安全的特性。它旨在防止 XSRF(跨网站请求伪造)攻击。 -为了理解它什么时候起效,我们来介绍下以下的攻击情况。 +为了了解它是如何工作的,以及何时有用,让我们看一下 XSRF 攻击。 ### XSRF 攻击 -想象一下,你登录了 `bank.com` 网站。此时:你有了该站点的身份验证 cookie。你的浏览器会随着每次请求把它发送到 `bank.com`,因此,`bank.com` 承认你的身份和你做出的所有敏感经济操作。 +想象一下,你登录了 `bank.com` 网站。此时:你有了来自该网站的身份验证 cookie。你的浏览器会在每次请求时将其发送到 `bank.com`,以便识别你,并执行所有敏感的财务上的操作。 -现在,在另外一个窗口浏览网页时,你偶然访问了另外一个网站 `evil.com`,该网站有 JavaScript 代码提交了一个表单 `