JS之存储篇-cookie
引入
cookie是一种早期的客户端存储机制,用于存储少量的文本数据。cookie数据可以自动在浏览器和服务器之间传输,因此服务器端脚本可以读写存储在客户端的cookie。任何以cookie形式存储的数据,不论服务器端是否需要,每一次HTTP请求都会把这些数据传输到服务器端。
概述
在JavaScript中,cookie常用于保存状态以及能够为Web浏览器提供一种身份识别机制。但是,JavaScript中使用cookie不会采用任何加密机制,因此它们是不安全的。通过https来传输cookie数据是安全的,不过这和cookie本身无关,而和https协议相关
服务器可以通过发送Set-Cookie头设置会话信息
这个HTTP响应设置了一个名为token
、值为asdf
的cookie,名称和值在传送时必须都是经过URL编码的,浏览器会存储这些会话信息,并且会在此之后,为每个请求自动添加Cookie HTTP头,用于把cookie信息发送回服务器
组成
一条cookie由以下7部分组成
Set-Cookie: Name=value[; Expires=date][; Max-Age=secondes][; Domain=domain][; Path=path][; Secure]
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.com
,admin.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,需要建立一系列新方法。