JS之存储篇-cookie

引入

cookie是一种早期的客户端存储机制,用于存储少量的文本数据。cookie数据可以自动在浏览器和服务器之间传输,因此服务器端脚本可以读写存储在客户端的cookie。任何以cookie形式存储的数据,不论服务器端是否需要,每一次HTTP请求都会把这些数据传输到服务器端。

概述

在JavaScript中,cookie常用于保存状态以及能够为Web浏览器提供一种身份识别机制。但是,JavaScript中使用cookie不会采用任何加密机制,因此它们是不安全的。通过https来传输cookie数据是安全的,不过这和cookie本身无关,而和https协议相关

服务器可以通过发送Set-Cookie头设置会话信息

JS之存储篇-cookie

这个HTTP响应设置了一个名为token、值为asdf的cookie,名称和值在传送时必须都是经过URL编码的,浏览器会存储这些会话信息,并且会在此之后,为每个请求自动添加Cookie HTTP头,用于把cookie信息发送回服务器

JS之存储篇-cookie

组成

一条cookie由以下7部分组成

Set-Cookie: Name=value[; Expires=date][; Max-Age=secondes][; Domain=domain][; Path=path][; Secure]

JS之存储篇-cookie

Name: cookie的名称,名称必须是经过URL编码的。cookie名称是不区分大小的,但实践中最好将cookie看作是区分大小的,因为某些服务器会这样处理cookie

token=asdf

value: cookie的值,值也必须是经过URL编码的

token=asdf

Expires: cookie有效期,表示cookie何时应该被删除,这个值是个GMT格式的日期(Wdy,DD-Mon-YYYY HH:MM:SS GMT),用于指定应该删除cookie的准确时间。默认情况下,浏览器会话结束时即将所有cookie删除(在HTTP1.1中已经被废弃,推荐使用Max-Age设置有效时间)

Expires=Thu, 09 Aug 2018 07:47:45 GMT

Max-Age: cookie有效期,单位秒

Max-Age=86400

注意: IE8-浏览器不支持Max-Age,如果需要兼容性IE8,可以同时设置expries和Max-Age

Domain: cookie的有效域。这个值可以包含子域(如example.comadmin.example.com),也可以不包含它(如.example.com,则对于example.com的所有子域都有效)。如果没有明确设定,那么这个域会被认作来自设置cookie的那个域

Domain=.example.com;

Path: cookie的有效路径,必须是绝对路径(比如/、/books),如果未指定,默认为请求该Cookie的网页路径。例如,可以指定cookie只有从http://www.example.com/books/中才能访问,那么http://www.example.com的页面就不会发送cookie信息,即使请求都是来自同一个域的

Path=/books

注意: 路径匹配不是绝对匹配,而是从根路径开始,只要path匹配到发送路径的一部分,就会发送cookie。比如path属性是'/books',则发送路径是'/booksart',cookie也会发送

Secure: 安全标志,指定该属性后,cookie只有在使用SSL连接(https)的时候才发送到服务器。Secure标志是cookie中唯一一个非名值对儿的部分,直接包含一个secure单词

注意: 域、路径、失效时间、有效期和安全标志都是服务器给浏览器的指示,以指定何时应该发送cookie。这些参数并不会作为发送到服务器的cookie信息的一部分,只有名值对儿才会被发送

读取

客户端可以通过document.cookie属性获取cookie值,返回一个由名值对组成的字符串。不同名值对之间通过“分号加空格”分隔。

console.log(document.cookie); // token=asdf; name=wmui

封装一个getCookie()函数,用于解析cookie

function getCookie(cookie) {
  var arr = cookie.split('; '), obj = {};
  for (var i = 0; i < arr.length; i++) {
    var c = arr[i].split('=');
    var key = decodeURIComponent(c[0]), value = decodeURIComponent(c[1]);
    obj[key] = value;
  }
  return obj;
}
console.log(getCookie(document.cookie)) // {token: "asdf", name: "wmui"}

设置

前端在设置cookie的时候,格式和Set-Cookie头中使用的格式一样。设置表示新增一条cookie,如果cookie名称已存在,会覆盖原来的cookie值。设置的新cookie同样会随请求自动发送到服务器

document.cookie = 'name=wmui';
document.cookie = 'token=asdf; Max-Age=86400';

由于cookie的名/值中的值是不允许包含分号、逗号和空白符,因此,在存储前应该采用encodeURIComponent()对值进行编码

document.cookie = encodeURIComponent('name') + '=' + encodeURIComponent('wmui')

封装一个setCookie()函数,用于设置cookie

/*
 * options参数:maxAge、path、secret、expires
 * 客户端设置domain是无效的,因为只能是当前域
 */
function setCookie(key, value, options) {
  var cookie = encodeURIComponent(key) + '=' + encodeURIComponent(value) + '; ';
  for(var k in options) {
    // 首字母大写,驼峰转下换线
    var newkey = k.replace(/^\S/, function($1) {
      return $1.toUpperCase();
    }).replace(/\B[A-Z]/g,function($1) {
      return '-' + $1
    })
    if(newkey === 'Secure') {
      cookie += 'Secure; '
    }else{
      cookie += newkey +'=' + options[k] + '; '
    }
  }
  document.cookie = cookie
}
setCookie('token', 'asdf', {
  maxAge: 24 * 60 * 60
}

cookie一次只能设置一个,多次写入需要多次调用setCookie()方法

修改

直接重新设置原来的cookie的值即可

setCookie('token', 'aaaa', {
  maxAge: 24 * 60 * 60
}

删除

把要删除的cookie的值设置为非空、Max-Age设置为0即可删除

setCookie('token', 'aaaa', {
  maxAge: 0
}

标识

window.navigator.cookieEnabled属性返回一个布尔值,表示浏览器是否打开Cookie功能。浏览器默认是打开Cookie功能的

console.log(window.navigator.cookieEnabled) // true

限制

cookie在性质上是绑定在特定的域名下的,这个限制确保了储存在cookie中的信息只能让批准的接受者访问,而无法被其他域访问。

每个域的cookie总数是有限的,不过浏览器之间各有不同,为了保持兼容性,最好是保持在30条以内。超过限制后浏览器会删除一些cookie,以便腾出空间容纳新的cookie

除了条数,cookie大小也是有限制的,大多数浏览器都有大约4kb的长度限制,超过大小后将无法再设置新的cookie。这里的大小指的是一个域下的所有cookie,而不是一条cookie的大小

共享

对于不同的网址,只要域名和端口相同,就可以共享Cookie。这里不要求协议相同,所以http://example.com设置的Cookie,可以被https://example.com读取

子cookie

为了绕开浏览器的单域名下的cookie数限制,一些开发人员使用了一种称为子cookie(subcookie)的概念。子cookie是存放在单个cookie中的更小段的数据,格式如下

name=name1=value1&name2=value2&name3=value3&name4=value4&name5=value5

使用子cookie的优势是,Web应用程序可以无需达到单域名cookie上限也可以存储更加结构化的数据。但是由于其结构更加复杂,为了更好地操作子cookie,需要建立一系列新方法。

上一篇:Java题目分析


下一篇:ES6 — class类