cookie最初是设计给服务端用的。若是客户端有cookie,则每次请求都会发给服务端。下面来具体看一下这个机制。node
就像上面说的,cookie最初是设计给服务端使用的。cookie就像服务端给这个客户端加的一个标签,当客户端再次请求时,会带着这个标签,那么服务器就能经过携带的cookie知道当前的客户端是谁了。api
cookie的设置过程大致以下:跨域
Cookie主要用于如下三个方面:数组
会话状态管理(如用户登陆状态、购物车、游戏分数或其它须要记录的信息)浏览器
个性化设置(如用户自定义设置、主题等)缓存
浏览器行为跟踪(如跟踪分析用户行为等)安全
cookie 是能够被修改的,客户端和服务端均可以对已经设置的cookie进行修改。服务器
在1.1部分的cookie设置过程当中可知,若是客户端将原本是 Joey的 cookie 改为 Ross,那么服务器就会认为如今发请求的客户端是 Ross,可能会给客户端 Joey 返回原本属于 Ross 的内容。这确定是不该该的。cookie
因此说, cookie 是不可信的。网络
客户端在得到服务端返回的 cookie 后,在之后再给服务器发请求时,不管服务端是否是想要 cookie, 都会放在请求里发过去。
咱们知道,网络请求是很是耗时间的,若是cookie过大,每次请求服务器时都会在 header 中带上 cookie ,则网络请求时间会过长。
因此大多数浏览器都对每一个域的cookie数量和大小有限制,每一个浏览器对cookie数量的限制不相同,但对总大小的限制大都是4096B。
若是新加入的cookie要超过了浏览器的最大数量限制,会删除较早的 cookie 以腾出空间。不一样浏览器的删除策略不一样,有的会删除最近最少使用的 cookie,例如 IE和Opera;有些彷佛会随机选择一个来删除,例如 Firefox...
若是新的加入新的 cookie 以后全部 cookie 的总大小超过限制,则新的 cookie 不会设置成功, 会被丢弃。
因此,不要设置太多 cookie, 以避免出现意料不到的事情。
cookie由如下几个字段组成:
name
:名称,惟一值,用来惟一识别cookie,不分大小写。必须通过 URL 编码value
:值,对应于名称,必须通过 URL 编码domain
:域,设置cookie对于哪一个域是有效的,都向这个域里发cookie。例如domain值为www.baidu.com,则全部发向这个网址的请求,都会发这个cookiepath
:路径,指定域里的路径能够接受这个cookie,例如百度下的/search路径:www.baidu.com/searchexpires
:过时时间,表示这个cookie何时应该被删除,这是个日期格式的。若是没有定义,cookie会在对话结束时过时。若是想让一个cookie立刻过时,则能够将这个值设置成过去的时间。max-age
:过时倒计时,以秒为单位。若是设置成0,则这个cookie马上失效,设置负数时不会产生cookie文件secure
:设置该 cookie 只经过https协议传输,这不是键值对,是个标记,写上就表明设置为只在使用 https 传输。从 Chrome 52 和 Firefox 52 开始,不安全的站点使用http协议的站点没法使用Cookie的 Secure
标记http-only
:设置不容许在浏览器端用 JavaScript 获取到 cookie。这也不是个键值对,是个标记,写上就表明生效。能够用来防止跨域脚本(XSS )攻击samesite
:要求cookie在跨站请求时不会被发送,防止跨站请求伪造(CSRF)的特性,可取值其中除name: value
为必须以外,其他都是可选项。
在客户端使用 JavaScript 对 cookie 的操做能够分为两类,分别是读取 cookie 和 设置 cookie,下面分别进行讨论。
BOM 的提供的操做 cookie 的 api 看起来有些难用。
使用 document.cookie 便可得到该页面中全部的 cookie,例如,咱们来看看百度学术给我设置了什么cookie。打开http://xueshu.baidu.com/。按F12,打开上部分的 Application 选项卡,而后打开左侧的 cookies。
百度学术在个人电脑里保存的cookie如图:
而后在命令台上经过 document.cookie 来获取页面里的 cookie:
// 获取 cookie, 获得的是全部 cookie 组成的字符串
let cookies = document.cookie;
// 提取出全部的 cookie 到数组中
let cookieArray = cookies.split(';');
// 用 console.table 输出cookie数组,这样比较清晰
console.table(cookieArray);
复制代码
结果以下:
能够看到经过 document.cookie 获取的 cookie 的 name 和 value 与浏览器工具获得的相同。
以图中第一个cookie为例,cookie 名为 PSTM , value 是1563885xxx,域名是 .baidu.com,过时时间是2087年8月10号,其余属性都取默认值。
给 document.cookie 赋一个新的 cookie 字符串能够设置一个新的 cookie 了。
以MDN为例,在这个网站域名下设置一个本身的cookie,配置以下:
其余选项不设置,也就是取默认值。
设置以前的 cookie 为:
设置:
let name = 'username',
value = 'test',
domain = '.mozilla.org',
path = '/';
var myCookie = encodeURIComponent(name) + '=' + encodeURIComponent(value) + ';domain=' + domain + ';path=' + path;
document.cookie = myCookie;
复制代码
结果以下:
能够看到 cookie 设置成功了。
因为不一样服务端程序的在响应报文的头部设置 set-cookie 操做的具体代码不一样,这里以 node.js 的 koa 框架为例。
先起一个极简的 server,而后对于访问者返回的报文的 header 都设置 set-cookie 头部:
const Koa = require('koa');
const app = new Koa();
app.use(async ctx => {
ctx.cookies.set('koa_cookie_name', 'koa_cookie_value');
ctx.body = 'cookie setted';
});
app.listen(3001, (e) => {
console.log('server listening port 3001');
});
复制代码
进入'http://localhost:3001/'后去查看 cookie:
能够看到服务端传来的 cookie。
sessionStorage 和 localStorage 有与cookie不一样的两点:
sessionStorage 和 localStorage 都是 Storage 对象;都是以名值对的形式存储数据,存储数据的key和value都是字符串(string)类型,若是传入的不是字符串类型,会被转换为字符串类型。
因此,若是想把非字符串类型的数据存进来,要预先手动进行编码,取出来后要再进行解码。
这两类对象有着相同的增删改查数据的 api,因此能够用其中的一个对象为例子,来演示这些 api,这里选择 sessionStorage :
setItem(key, value)
:将一个键值对的保存,若是两次保存的key相同可是value不一样,则后面的覆盖前面的。getItem(key)
:获取指定 key 对应的 valueremoveItem(key)
:删除指定的 key 及其 valuekey(index)
:获取指定位置的...clear()
:删除全部数据还有一个属性:
length
属性:判断存了多少名值对,上面key(index)
方法中的参数 index 的范围是 0 =< index <= length - 1使用sessionStorage来演示上面的 api:
存入两个键值对,使用
setItem(key, value)
方法:
sessionStorage.setItem('key 1', 'value 1');
sessionStorage.setItem('key 2', 'value 2');
复制代码
打开浏览器页面的开发者工具,点击Application选项卡,点击左侧的 session Storage,就能看到两条刚刚保存的键值对了。
获取两个键对应的数据,使用
getItem(key)
方法:
let value1 = sessionStorage.getItem('key 1');
let value2 = sessionStorage.getItem('key 2');
console.log(value1, value2); // value 1 value 2
复制代码
删除
'key 1'
和其对应的数据,使用removeItem(key)
方法:
sessionStorage.removeItem('key 1');
复制代码
从图中能够看到存储的数据只剩下 key 2: value 2 了。
如今再添加几条数据:
sessionStorage.setItem('key 3', 'value 3');
sessionStorage.setItem('key 4', 'value 4');
sessionStorage.setItem('key 5', 'value 5');
sessionStorage.setItem('key 6', 'value 6');
复制代码
获得:
输出如今存储的数据条数,也就是键值对的条数,并输出最后一条,使用
length
属性:
let key_value_count = sessionStorage.length;
console.log('如今存储了 ' + key_value_count + ' 条数据'); // 如今存储了 5 条数据
复制代码
一次性删除全部数据,使用
clear()
方法:
sessionStorage.clear();
复制代码
结果:
因为 Storage 自己就是对象,因此也可使用通常对象的读取与设置属性的语法来存取对象,本质就是经过设置属性和值的键值对来添加与读取数据。
存取的方式也和普通对象同样有两种,分别是点号法和中括号语法,例以下面的例子:
sessionStorage.key1 = 'value 1';
console.log(sessionStorage.key1);
sessionStorage['key 2'] = 'value 2';
console.log(sessionStorage['key 2']);
复制代码
结果如图:
这种语法和 api 中的 setItem
和getItem
效果相同。
想删除一个数据时,可使用 delete
关键字,和删除普通对象属性的操做相同:
delete sessionStorage.key1;
delete sessionStorage['key 2'];
复制代码
结果:
这和 removeItem
的效果相同。
sessionStorage 和 localStorage 的区别在声明周期和做用域这两点上,具体来讲以下。
在 Storage 里的数据被添加、修改、删除时,会触发 storage 事件,能够在 window 对象上添加事件监听程序 onstorage 来监听事件,而且能够获取事件对象。
storage 事件对象上有以下几个属性:
注意:localStorage 的事件采用的是广播机制,正在访问相同站点的页面都会受到信息。这样能够完成必定的标签页之间的通讯。
参考:
MDN
《JavaScript高级程序设计》
《JavaScript权威指南》