本文由云 + 社区发表
在前端面试中,有一个必问的问题:请你谈谈 cookie 和 localStorage 有什么区别啊?
localStorage 是 H5 中的一种浏览器本地存储方式,而实际上,cookie 本身并不是用来做服务器存储的。但在 localStorage 出现之前,cookie 被滥用当做了存储工具,什么数据都放在 cookie 中,即使这些数据只在页面中使用、而不需要随请求传送到服务端(当然 cookie 也做了一些限制:大小受限、每个域名下生成的 cookie 数量受限)。就像 CSS 中的 float,最初被设计出来的初衷,是用于做文字环绕效果的,就是一个图片、一段文字,给图片加上 float:left 的样式后,就会产生文字环绕图片的效果。但是后来发现 float 结合 <div>,可以实现之前通过 <table> 实现的网页布局,因此就被“误用于”网页布局了。
那么通过阅读本文,你可以了解:
1.cookie 是什么,cookie 的属性有哪些,如何设置 cookie,cookie 的缺点,和 session 的区别 2. 不再混淆 cookie 和 webStorage,简单介绍浏览器的本地存储的两种方式:sessionStorage 和 localStorage
1.cookie
1.1 cookie 是什么
cookie 是当你浏览某个网站的时候,由 web 服务器存储在你的机器硬盘上的一个小的文本文件。它其中记录了你的用户名、密码、浏览的网页、停留的时间等等信息。当你再次来到这个网站时,web 服务器会先看看有没有它上次留下来的 cookie。如果有的话,会读取 cookie 中的内容,来判断使用者,并送出相应的网页内容,比如在页面显示欢迎你的标语,或者让你不用输入 ID、密码就直接登录等等。
当客户端要发送 http 请求时,浏览器会先检查下是否有对应的 cookie。有的话,则自动地添加在 request header 中的 cookie 字段。注意,每一次的 http 请求时,如果有 cookie,浏览器都会自动带上 cookie 发送给服务端。那么把什么数据放到 cookie 中就很重要了,因为很多数据并不是每次请求都需要发给服务端,毕竟会增加网络开销,浪费带宽。所以对于那设置“每次请求都要携带的信息(最典型的就是身份认证信息)”就特别适合放在 cookie 中,其他类型的数据就不适合了。
简单的说就是:
(1) cookie 是以小的文本文件形式(即纯文本),完全存在于客户端;cookie 保存了登录的凭证,有了它,只需要在下次请求时带着 cookie 发送,就不必再重新输入用户名、密码等重新登录了。
(2) 是设计用来在服务端和客户端进行信息传递的;
这里我简单地画了个图,可以方便理解:
第一次请求时:
第一次请求
下一次请求时:
下一次请求
浏览器会把 cookie 放到请求头一起提交给服务器,cookie 携带了会话 ID 信息。服务器会根据 cookie 辨认用户:由于 cookie 带了会话的 ID 信息,可以通过 cookie 找到对应会话,通过判断会话来判断用户状态。
1.2 cookie 的属性
在浏览器的控制台中,可以直接输入:document.cookie 来查看 cookie。cookie 是一个由键值对构成的字符串,每个键值对之间是“;”即一个分号和一个空格隔开。
document.cookie
注意,这个方法只能获取非 HttpOnly 类型的 cookie
每个 cookie 都有一定的属性,如什么时候失效,要发送到哪个域名,哪个路径等等。这些属性是通过 cookie 选项来设置的,cookie 选项包括:expires、domain、path、secure、HttpOnly。在设置任一个 cookie 时都可以设置相关的这些属性,当然也可以不设置,这时会使用这些属性的默认值。在设置这些属性时,属性之间由一个分号和一个空格隔开。代码示例如下:
“key=name; expires=Sat, 08 Sep 2018 02:26:00 GMT; domain=ppsc.sankuai.com; path=/; secure; HttpOnly”
cookie 的属性可以在控制台查看:Application 选项,左边选择 Storage,最后一个就是 cookie,点开即可查看。
Expires、Max Age:
Expires 选项用来设置“cookie 什么时间内有效”。Expires 其实是 cookie 失效日期,Expires 必须是 GMT 格式的时间(可以通过 new Date().toGMTString() 或者 new Date().toUTCString() 来获得)。
new Date().toGMTString() 或者 new Date().toUTCString()
如 expires=Sat, 08 Sep 2018 02:26:00 GMT 表示 cookie 将在 2018 年 9 月 8 日 2:26 分之后失效。对于失效的 cookie 浏览器会清空。如果没有设置该选项,这样的 cookie 称为会话 cookie。它存在内存中,当会话结束,也就是浏览器关闭时,cookie 消失。
补充:
Expires 是 http/1.0 协议中的选项,在 http/1.1 协议中 Expires 已经由 Max age 选项代替,两者的作用都是限制 cookie 的有效时间。Expires 的值是一个时间点(cookie 失效时刻 = Expires),而 Max age 的值是一个以秒为单位时间段(cookie 失效时刻 = 创建时刻 + Max age)。另外,Max age 的默认值是 -1(即有效期为 session);Max age 有三种可能值:负数、0、正数。负数:有效期 session;0:删除 cookie;正数:有效期为创建时刻 + Max age
Domain 和 Path
Domain 是域名,Path 是路径,两者加起来就构成了 URL,Domain 和 Path 一起来限制 cookie 能被哪些 URL 访问。即请求的 URL 是 Domain 或其子域、且 URL 的路径是 Path 或子路径,则都可以访问该 cookie,例如:
某 cookie 的 Domain 为“baidu.com”, Path 为“/”,若请求的 URL(URL 可以是 js/html/img/css 资源请求,但不包括 XHR 请求) 的域名是“baidu.com”或其子域如“api.baidu.com”、“dev.api.baidu.com”,且 URL 的路径是“/”或子路径“/home”、“/home/login”,则都可以访问该 cookie。
补充:
发生跨域 xhr 请求时,即使请求 URL 的域名和路径都满足 cookie 的 Domain 和 Path,默认情况下 cookie 也不会自动被添加到请求头部中。
Size
Cookie 的大小
Secure
Secure 选项用来设置 cookie 只在确保安全的请求中才会发送。当请求是 HTTPS 或者其他安全协议时,包含 Secure 选项的 cookie 才能被发送至服务器。
默认情况下,cookie 不会带 Secure 选项 (即为空)。所以默认情况下,不管是 HTTPS 协议还是 HTTP 协议的请求,cookie 都会被发送至服务端。但要注意一点,Secure 选项只是限定了在安全情况下才可以传输给服务端,但并不代表你不能看到这个 cookie。
补充:
如果想在客户端即网页中通过 js 去设置 Secure 类型的 cookie,必须保证网页是 https 协议的。在 http 协议的网页中是无法设置 secure 类型 cookie 的。
httpOnly
这个选项用来设置 cookie 是否能通过 js 去访问。默认情况下,cookie 不会带 httpOnly 选项 (即为空),所以默认情况下,客户端是可以通过 js 代码去访问(包括读取、修改、删除等)这个 cookie 的。当 cookie 带 httpOnly 选项时,客户端则无法通过 js 代码去访问(包括读取、修改、删除等)这个 cookie。
在客户端是不能通过 js 代码去设置一个 httpOnly 类型的 cookie 的,这种类型的 cookie 只能通过服务端来设置。
可以在浏览器的控制台中看出哪些 cookie 是 httpOnly 类型的,HTTP 下带绿色对勾的即是,如图:
httponly
只要是 httponly 类型的, 在控制台通过 document.cookie 是获取不到的,也不能进行修改。
之所以限制客户端去访问 cookie,主要还是出于安全的目的。因为如果任何 cookie 都能被客户端通过 document.cookie 获取,那么假如合法用户的网页受到了 XSS 攻击,有一段恶意的 script 脚本插到了网页中,这个 script 脚本,通过 document.cookie 读取了用户身份验证相关的 cookie,那么只要原样转发 cookie,就可以达到目的了。
1.3 cookie 的设置、读取、删除方法
cookie 既可以由服务端来设置,也可以由客户端来设置。
1.3.1 服务端设置 cookie
前面 1.1 中介绍过,客户端第一次向服务端请求时,在相应的请求头中就有 set-cookie 字段,用来标识是哪个用户。
下图我是登录腾讯云的某个页面的响应头截图,可以看到响应头中有两个 set-cookie 字段,每段对应一个 cookie,注意每个 cookie 放一个 set-cookie 字段中,不能将多个 cookie 放在一个 set-cookie 字段中。具体每个 cookie 设置了相关的属性:expires、path、httponly,具体属性含义可以结合 1.2 cookie 的属性来看:
response headers
服务端设置 cookie 的范围:
服务端可以设置 cookie 的所有选项:expires、domain、path、secure、HttpOnly
1.3.2 客户端设置 cookie
cookie 不像 web Storage 有 setItem,getItem,removeItem,clear 等方法,需要自己封装。简单地在浏览器的控制台里输入:
document.cookie=”name=lynnshen; age=18″
但发现只添加了第一个 cookie:”name=lynnshen”,后面的 cookie 并没有添加进来:
最简单的设置多个 cookie 的方法就是重复执行 document.cookie = “key=name”:
document.cookie = “name=lynnshen”;
document.cookie = “age=18”;
再看控制台:
注意:
当 name、domain、path 这 3 个字段都相同的时候,cookie 会被覆盖。
下面是我自己简单封装的设置、读取、删除 cookie 的方法:
设置 cookie:
function setCookie(name,value,iDay){
var oDate = new Date();
oDate.setDate(oDate.getDate() + iDay);
document.cookie = name + “=” + value + “;expires=” + oDate;
}
读取 cookie,该方法简单地认为 cookie 中只有一个“=”,即 key=value,如有更多需求可以在此基础上完善:
function getCookie(name){
// 例如 cookie 是 ”username=abc; password=123″
var arr = document.cookie.split(‘; ‘);// 用“;”和空格来划分 cookie
for(var i = 0 ;i < arr.length ; i++){
var arr2 = arr[i].split(“=”);
if(arr2[0] == name){
return arr2[1];
}
}
return “”;// 整个遍历完没找到,就返回空值
}
删除 cookie:
function removeCookie(name){
setCookie(name, “1”, -1)// 第二个 value 值随便设个值,第三个值设为 - 1 表示:昨天就过期了,赶紧删除
}
1.4 cookie 的缺点
cookie 的缺点:
(1) 每个特定域名下的 cookie 数量有限:
IE6 或 IE6-(IE6 以下版本):最多 20 个 cookie
IE7 或 IE7+(IE7 以上版本):最多 50 个 cookie
FF: 最多 50 个 cookie
Opera: 最多 30 个 cookie
Chrome 和 safari 没有硬性限制
当超过单个域名限制之后,再设置 cookie,浏览器就会清除以前设置的 cookie。IE 和 Opera 会清理近期最少使用的 cookie,FF 会随机清理 cookie;
(2) 存储量太小,只有 4KB;
(3) 每次 HTTP 请求都会发送到服务端,影响获取资源的效率;
(4) 需要自己封装获取、设置、删除 cookie 的方法;
1.5 cookie 和 session 的区别
cookie 是存在客户端浏览器上,session 会话存在服务器上。会话对象用来存储特定用户会话所需的属性及配置信息。当用户请求来自应用程序的 web 页时,如果该用户还没有会话,则服务器将自动创建一个会话对象。当会话过期或被放弃后,服务器将终止该会话。cookie 和会话需要配合,具体内容参见 1.1 节。
当 cookie 失效、session 过期时,就需要重新登录了。
2. 浏览器本地存储:
2.1 localStorage 和 sessionStorage
在较高版本的浏览器中,js 提供了两种存储方式:sessionStorage 和 globalStorage。在 H5 中,用 localStorage 取代了 globalStorage。
sessionStorage 用于本地存储一个会话中的数据,这些数据只有在同一个会话中的页面才能访问,并且当会话结束后,数据也随之销毁。所以 sessionStorage 仅仅是会话级别的存储,而不是一种持久化的本地存储。
localStorage 是持久化的本地存储,除非是通过 js 删除,或者清除浏览器缓存,否则数据是永远不会过期的。
浏览器的支持情况:IE7 及以下版本不支持 web storage,其他都支持。不过在 IE5、IE6、IE7 中有个 userData,其实也是用于本地存储。这个持久化数据放在缓存中,只有不清理缓存,就会一直存在。
2.2 web storage 和 cookie 的区别
(1) web storages 和 cookie 的作用不同,web storage 是用于本地大容量存储数据 (web storage 的存储量大到 5MB); 而 cookie 是用于客户端和服务端间的信息传递;
(2) web storage 有 setItem、getItem、removeItem、clear 等方法,cookie 需要我们自己来封装 setCookie、getCookie、removeCookie,具体可见 1.3 节;
3. 小结
本文纵向上深度介绍了 cookie 相关的知识,包括 cookie 的作用、各个属性的用途、cookie 的设置、缺点等等。横向上,将 cookie 和会话、localStorage 做了比较。如有问题,欢迎指正。
此文已由作者授权腾讯云 + 社区发布
搜索关注公众号「云加社区」,第一时间获取技术干货,关注后回复 1024 送你一份技术课程大礼包!