Cookie

我们的老朋友--Cookie免费看

Cookie存储的使用详解

2018-08-17侠课岛    初级拔高       

前端/前端/客户端存储 12     0     3800

2.1 Cookie 介绍

这一章我们来介绍一下我们的老朋友—— Cookie。Cookie 诞生于 HTTP 1.0 时代,主要用于处理 HTTP 请求无状态的问题,与服务端的 Session 一起配合使用,可以记录网站用户的登录状态。作为最古老也是最稳定的客户端存储手段,一直沿用至今。

Cookie 在第一次与服务器通讯时由服务器设定并返回给浏览器,之后浏览器的每一次请求都会在 HTTP 头部带上 Cookie。一般情况下,我们每一次刷新页面或者点击链接跳转时 Cookie 都会被发到服务器用于验证我们的身份。服务器往往会在设置一个类似 id 的字段(一般会叫做 sid)来作为身份的凭据。有时也会设置一些其他的内容储存在客户端中。最常见的应用就是当我们登录某个论坛或者网站之后,在一段时间内可以不用重复进行登录。

Cookie 与服务器交互的示意图

Cookie 中虽然可以存放信息,但一般情况下(尤其是现代前端开发)我们不会将其作为存放数据的主要手段。主要原因有以下几点。

  1. 安全性:Cookie 很容易被读取。因为本身就作为 document 的属性之一,我们在控制台通过 document.cookie 就能获取 Cookie 的内容(在 Chrome 的开发者工具中可以看到格式化后的数据)。并且 Cookie 最终是以文件的形式存放在本地,那么查看和修改就十分方便,这也是不建议存放敏感数据的原因。
  2. 传输性:由于 Cookie 是放在 HTTP 请求头中发出,因此在传输时会占用一定的带宽,所以过多的内容就会增加传输的负担。一般情况下不会建议 Cookie 的大小超过 4KB(这是过去的限制,现在虽然没有明确限制了,但仍然不建议存放过多的内容。毕竟我们已经有了其他更好的手段了)。
  3. 易用性:虽然说 Cookie 是以 cookieName=Value; 这样的键值对的形式赋值。但本质上仍然是一个字符串,typeof document.cookie 返回的是 string。这也就意味着,我们在操作 Cookie 时实际上需要进行字符串操作(虽然有对应的类库可以帮助我们)。这与 Web 存储(LocalStorage/SessionStorage)的操作相比就要复杂多了。

在正式介绍 Cookie 的使用方法前,我们就先在 Chrome 开发者工具的 Application 中来看一下 Cookie 有哪些属性。下图为 B站 的 Cookie 截图。

编号 名称 作用
1 Name 表示 Cookie 中属性的名称。
2 Value 对用上面 Name,表示 Cookie 中属性对应的值。
3 Domain 表示可以访问此 Cookie 的域名。如上面 .bilibili.com 为顶级域名,下面的二级域名都可以访问此 Cookie,而 .live.bilibili.com 的 Cookie 则只有这个域名才能访问,其他二级域名是无法访问的。
4 Path 与 Domain 类似,指定允许访问的路径。如 .bilibili.com/abc 这样的页面。若允许所有页面访问,则为 /
5 Expires/Max-Age 表示该条 Cookie 的过期时间,当超过该时间时,Cookie 会自动失效。如果不设置,则默认为 Session,即浏览器关闭后就失效。
6 Size 表示这一条 Cookie 的大小。
7 HTTP 表示 Cookie 的 HTTPONLY 属性。若为 ture, 则在 HTTP 请求头中会带有此 Cookie,并且不能通过 document.cookie 来访问。
8 Secure 用来设置该 Cookie 能否只通过 HTTPS 来进行传输。
9 SameSite 定义 Cookie 如何跨域发送,用来防止 CSRF 攻击。是谷歌开发的一种安全机制,有 Strict 和 Lax 两种属性。目前在后端的支持度还不高,基本没有相关的 API 来操作(需要走更底层的操作)。

2.2 Cookie 的使用方法

在上面我们了解了 Cookie 的一些属性,那么这一小节我们将介绍 Cookie 的使用方法。对上面属性还不熟悉的小伙伴可以先复习一下再继续哦~

2.2.1 Cookie 的写入

因为 JavaScript 自带了 document.cookie 的方法,我们可以直接通过 document.cookie='name=Value;' 的方法来写入 Cookie。在这里,我们就直接通过控制台向 B站的 Cookie 中再添加两条。(仅做测试不设置过期时间,这样浏览器关闭后就会失效,不会产生影响)

document.cookie='name=Konata9'
document.cookie='age=17'

输入完成后,我们再回到开发者工具的 Application 面板。就可以看到我们刚才添加的两条 Cookie 了。

这里需要注意的是,不同于我们一般对于 JavaScript 操作的认识。我们刚才对 document.cookie 连续赋值之后,age 并不会覆盖之前的 name,而是会增加一条。通常对于一个网站来说,Cookie 不建议超过 20 个。虽然在客户端这边并没有做硬性的规定,但在服务端那边过多的 Cookie 可能会带来意想不到的问题。

2.2.2 Cookie 的读取

读取的方法也十分简单,我们直接使用 document.cookie 来进行读取。在 Chrome 的控制台中,我们可以看到以下的输出结果(测试网站仍然是 B站)。

不过这样的形式对于我们非常地不友好。因为我们只能获取整段的字符串,如果要在程序中对某个属性进行处理的话,就必须要对整个字符串进行处理。尽管 cookie 字符串的分隔符还算明显 ;=,但处理起来仍然需要一些步骤。

当然,类似的库自然是已经有了。在这里我们介绍一下 Mozllia 提供了一套封装好的库。代码我们可以在 MDN 的页面上找到。这里我们将代码复制下来保存成 cookie.js(后面我们称这库为 cookie.js)方便我们后面使用。

/*\
|*|
|*|  :: cookies.js ::
|*|
|*|  A complete cookies reader/writer framework with full unicode support.
|*|
|*|  https://developer.mozilla.org/en-US/docs/DOM/document.cookie
|*|
|*|  This framework is released under the GNU Public License, version 3 or later.
|*|  http://www.gnu.org/licenses/gpl-3.0-standalone.html
|*|
|*|  Syntaxes:
|*|
|*|  * docCookies.setItem(name, value[, end[, path[, domain[, secure]]]])
|*|  * docCookies.getItem(name)
|*|  * docCookies.removeItem(name[, path], domain)
|*|  * docCookies.hasItem(name)
|*|  * docCookies.keys()
|*|
\*/

var docCookies = {
  getItem: function (sKey) {
    return decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null;
  },
  setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) {
    if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { return false; }
    var sExpires = "";
    if (vEnd) {
      switch (vEnd.constructor) {
        case Number:
          sExpires = vEnd === Infinity ? "; expires=Fri, 31 Dec 9999 23:59:59 GMT" : "; max-age=" + vEnd;
          break;
        case String:
          sExpires = "; expires=" + vEnd;
          break;
        case Date:
          sExpires = "; expires=" + vEnd.toUTCString();
          break;
      }
    }
    document.cookie = encodeURIComponent(sKey) + "=" + encodeURIComponent(sValue) + sExpires + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "") + (bSecure ? "; secure" : "");
    return true;
  },
  removeItem: function (sKey, sPath, sDomain) {
    if (!sKey || !this.hasItem(sKey)) { return false; }
    document.cookie = encodeURIComponent(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + ( sDomain ? "; domain=" + sDomain : "") + ( sPath ? "; path=" + sPath : "");
    return true;
  },
  hasItem: function (sKey) {
    return (new RegExp("(?:^|;\\s*)" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(document.cookie);
  },
  keys: /* optional method: you can safely remove it! */ function () {
    var aKeys = document.cookie.replace(/((?:^|\s*;)[^\=]+)(?=;|$)|^\s*|\s*(?:\=[^;]*)?(?:\1|$)/g, "").split(/\s*(?:\=[^;]*)?;\s*/);
    for (var nIdx = 0; nIdx < aKeys.length; nIdx++) { aKeys[nIdx] = decodeURIComponent(aKeys[nIdx]); }
    return aKeys;
  }
};

本教程图文或视频等内容版权归侠课岛所有,任何机构、媒体、网站或个人未经本网协议授权不得转载、转贴或以其他方式复制发布或发表。

评价

12

本课评分:
  •     非常好
难易程度:
  •     适中的
|
教程
粉丝
主页

签到有礼

已签到2天,连续签到7天即可领取7天全站VIP

  • 1
    +2 金币
  • 2
    +3 金币
  • 3
    +5 金币
  • 6
    +7 金币
  • 5
    +6 金币
  • 4
    暖心福利
    自选分类VIP ×1天
  • 7
    惊喜大礼

    自选分类VIP ×3天 +20金币
  • 持续签到 +8 金币

金币可以用来做什么?