HTTP 协议当初为了让协议尽量简洁,制定为无状态协议,即指每次 request 请求之前是相互独立的,当前请求并不会记录它的上一次请求信息。那么问题来了,开发中经常需要用到状态记录,比如日常的登录网站,不可能每次登录都要客户重新输入密码,这样用户体验肯定会很差,那如何让无状态的 http 协议将状态记录下来呢?
于是浏览器厂商发明了 cookie 来解决这个难题。
Cookie 总是保存在客户端中,按在客户端中的存储位置,可分为内存 Cookie 和硬盘 Cookie,设置了过期时间 Expires(Cookie 的几个属性之一)的 Cookie 会存储在硬盘里面,不同操作系统 cookie 的储存路径会有所不同,而没有设置该属性的 Cookie 会存储在内存里面,此时浏览器的选项卡可以共享同一个 cookie 信息,关闭浏览器就会清除该 Cookie!
首先看一下 cookie 在前后端交互中的应用:
第一次验证成功后,服务端会在响应头信息中带上“set-cookie”字段,浏览器监测到该字段之后,会把其中的值对号入座写入浏览器的 cookie 的属性中
存储在 cookie 中的数据,在它过期之前,每次都会 被浏览器自动放在 http 请求中,如果这些数据并不是每个请求都需要发给服务端的数据,浏览器这设置自动处理无疑增加了网络开销;但如果这些数据是每个请求都需要发给服务端的数据(比如身份认证信息),浏览器这设置自动处理就大大免去了重复添加操作。所以对于那设置“每次请求都要携带的信息(最典型的就是身份认证信息 token)”就特别适合放在 cookie 中。而服务器端通过验证 cookie 中的信息,实现了验证,也让浏览器端省去了每次都需要输入登录信息的麻烦。
为了实现 cookie 的作用,除了 name 和 value 之外,设计者还给它增加了七个属性,分别是expires/max-age、domain、path、secure、HttpOnly、samesite,这些属性是通过 cookie 选项来设置的,在设置任一个 cookie 时都可以设置相关的这些属性,当然也可以不设置,这时会使用这些属性的默认值。
Expires 和 Max-Age
expires 选项用来设置“cookie 什么时间内有效”。expires 其实是 cookie 失效日期,expires 必须是 GMT 格式的时间(可以通过 new Date().toGMTString()或者 new Date().toUTCString() 来获得)。
如 expires=Thu, 25 Feb 2016 04:18:00 GMT 表示 cookie 讲在 2016 年 2 月 25 日 4:18 分之后失效,对于失效的 cookie 浏览器会清空。如果没有设置该选项,则默认有效期为 session,即会话 cookie。这种 cookie 在浏览器关闭后就没有了,属于内存 cookie。而 max-age 就是 cookie 写入之后的有效时长,比如 max-age=600 就是 600 秒后,cookie 则会失效。max-age 的优先级高于 expires
domain 和 path
domain 是域名,path 是路径,两者加起来就构成了 URL,domain 和 path 一起来限制 cookie 能被哪些 URL 访问,domain 属性的默认值是创建 cookie 的网页所在服务器的主机名。不能将一个 cookie 的域设置成服务器所在的域之外的域,要想 cookie 在多个二级域名中共享,需要设置 domain 为顶级域名。
HttpOnly
告知浏览器不允许通过脚本 document.cookie 去更改这个值,同样这个值在 document.cookie 中也不可见。但在 http 请求张仍然会携带这个 cookie。注意这个值虽然在脚本中不可获取,但仍然在浏览器安装目录中以文件形式存在。
secure
安全标志,指定后,只有在使用 SSL 链接(https)时候才能发送到服务器,如果是 http 链接则不会传递该信息。就算设置了 secure 属性也并不代表他人不能看到你机器本地保存的 cookie 信息,所以不要把重要信息放在 cookie 中。
除了服务器端返回的 set-cookie 字段,浏览器端也可以对 cookie 进行操作,有 npm 为我们封装好的插件 js-cookie: https://www.npmjs.com/package…,不过我们还是用原生方法手动实现一遍
获取 cookie:
在控制台输入 document.cookie,或者 js 代码中 console.log(document.cookie)可以得到下图:
可以看到,cookie 是一个个键值对(“键 = 值”的形式)加上分号空格隔开组合而成,形如:“name1=value1; name2=value2; name3=value3″,可以用正则表达式来提取等号后面的值
function getCookie(name) {
var value = ';'+ document.cookie;
var parts = value.split(';' + name + '=');
if(parts.length === 2) {return parts.pop().split(';').shift();}
}
写入 cookie
function setCookie (name, value, day) {if(day !== 0){ // 当设置的时间等于 0 时,不设置 expires 属性,cookie 在浏览器关闭后删除
var expires = day * 24 * 60 * 60 * 1000
var date = new Date(+new Date()+expires);
document.cookie = name + "=" + escape(value) + ";expires=" + date.toUTCString()}else{document.cookie = name + "=" + escape(value)
}
}
注意:expires 使用 GMT 或 UTC 格式的时间,我这里没有指定路径 (path) 和域(domain),当没有指定路径时默认为当前路径下,如对 于“https://home.cnblogs.com/u/ma…”下设置的 cookie,其 path 为 ”/u/maderlzp”,其 domain 为当前域名“home.cnblogs.com”
删除 cookie
设置 cookie 过期时间小于当前时间,那么就会删除该 cookie
function deleteCookie(name) {document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:01 GMT;'}