随着技术的发展、网速的提升,浏览器做的事情也越来越多,能实现的功能也越来越丰富。而传统的C/S架构也基本被B/S架构给替代。
此时传统的Cookie已经远远不能满足我们的需求了。于是WebSQL、HTML5中本地存储(LocalStorage、SessionStorage)、IndexedDB等便适时出现,让前端可以彻底的大展手脚。
Cookie
Cookie在第一次与服务器通讯时由服务器设定并返回浏览器,之后浏览器的每一次请求都会在HTTP头部带上Cookie。一般情况下,我们每一次刷新页面或者点击链接跳转时Cookie都会被发到服务器用于验证我们的身份。服务器往往会在设置一个类似id的字段(一般会叫做sid)来作为身份的凭据。有时也会设置一些其他的内容储存在客户端中。最常见的应用就是当我们登录某个论坛或者网站之后,在一段时间内可以不用重复进行登录。
Cookie 与服务器交互的示意图
Cookie中虽然可以存放信息,但一般情况下(尤其是现代前端开发)我们不会将其作为存放数据的主要手段。主要原因有以下几点。
安全性:Cookie很容易被读取。因为本身就作为
document的属性之一,我们在控制台通过document.cookie就能获取Cookie的内容。并且Cookie最终是以文件的形式存放在本地,name查看和修改就十分方便,这也是不建议存放敏感数据的原因。传输性:由于Cookie是放在HTTP请求头中发出,因此在传输时会占用一定的带宽,所以过多的内容就会增加传输的负担。一般情况下不会建议Cookie的大小超过4KB。
易用性:虽然说Cookie是以
cookieName=Value;这样的键值对的形式赋值。但本质上仍然是一个字符串,typeof document.cookie返回的是string。这也就意味着,我们在操作Cookie时实际上需要进行字符串操作。这与Web存储(LocalStorage、SessionStorage)的操作相比就要复杂多了。Cookie的属性:
编号 名称 作用 1 Name 表示 Cookie 中属性的名称。 2 Value 对用上面 Name,表示 Cookie 中属性对应的值。 3 Domain 表示可以访问此 Cookie 的域名。如上面 .bilibili.com为顶级域名,下面的二级域名都可以访问此 Cookie,而.live.bilibili.com的 Cookie 则只有这个域名才能访问,其他二级域名是无法访问的4 Path 与 Domain 类似,指定允许访问的路径。如 .bilibili.com/abc这样的页面。若允许所有页面访问,则为/。5 Expires/Max-Age 表示该条 Cookie 的过期时间,当超过该时间时,Cookie 会自动失效。如果不设置,则默认为 Session,即浏览器关闭后就失效。 6 Size 表示这一条 Cookie 的大小。 7 HTTP 表示 Cookie 的 HTTPONLY 属性。若为 ture, 则在 HTTP 请求头中会带有此 Cookie,并且不能通过 document.cookie来访问。8 Secure 用来设置该 Cookie 能否只通过 HTTPS 来进行传输。 9 SameSite 定义 Cookie 如何跨域发送,用来防止 CSRF 攻击。是谷歌开发的一种安全机制,有 Strict 和 Lax 两种属性。目前在后端的支持度还不高,基本没有相关的 API 来操作(需要走更底层的操作)。
Cookie的使用方法
Cookie的写入
因为JavaScript自带了 document.cookie 的方法,我们可以直接通过 document.cookie='name=value;' 的方法来写入Cookie。
document.cookie = 'name=aye';
docuemnt.cookie = 'age=23';
docuemnt.cookie = 'userId=123; userName=aye';
document.cookie = 'str=' + escape('I love JavaScript');
我们刚才对document.cookie连续赋值之后,age并不会覆盖之前的name,而是会增加一条。如果要一次存储多个键值对,可以用分号加空格隔开。在Cookie的值中如果出现了分号、逗号、等号和空格需要用escape()函数进行编码,它能将一些特殊符号使用十六进制表示。当使用escape()编码后,在取值后需要使用unescape()进行解码才能获得原来的值。
Cookie的读取
我们直接使用document.cookie来进行读取,不过这样只能获取整段的字符串。尽管cookie字符串的分隔符还算明显;和=,但处理起来还需要一些步骤。这时我们可以使用一些库,在MDN上已有封装好的库了。主要API的用法如下。
- 写入 Cookie
docCookies.setItem(name, value[, end[, path[, domain[, secure]]]])其中name和value是必须的参数。剩下的参数为可选参数,含义可以参见上面表格。 - 读取
docCookies.getItem(name)通过name来获取 Cookie 的值,若不存在则返回null。注意这里获取的仍然是String类型的数据。 - 移除
Cookie docCookies.removeItem(name[, path],domain)移除指定name的 Cookie。本质上是将过期时间设置成一个过去的时间,从而让 Cookie 失效。 - 检查 Cookie
docCookies.hasItem(name)检查一个 Cookie 是否存在,返回布尔类型的值。 - 列出全部 Cookie
docCookies.keys()列出所有可读的 Cookie 的数组。
Cookie的删除
Cookie 并没有提供删除的 API。但是我们可以通过设置 max-age 或者 expires 来让 Cookie 失效,从而达到删除的效果。
max-age 和 expires 虽然在作用上是一样的,但是在实际的应用中,我们一般还是建议使用 max-age,主要的原因有下面几点。
max-age为秒数,expires为一个固定的 GMT 时间。而服务器与客户端可能会存在时间不同步的情况,因此就会引起问题。max-age的时间从文档第一次被服务器记录就开始计算,更为准确。
不过由于 expires 为 HTTP/1.0 中就已经存在了,对于遗留项目或需要向下兼容的项目,可能会用上。对于新的项目,还是建议采用 Cookie 或是其他代替技术。
小结
Cookie 作为最古老的客户端存储的手段陪伴着我们很多年了,但从实际使用来看也主要是用于一些属性的读写。即便在现在有许多代替技术的情况下也依旧在使用。不过由于 Cookie 的大小的限制、操作、安全性等问题,建议在做新项目的时候多考虑用其他技术来代替。
Cookie 与 Session 的区别
Cookie和Session本质上没有区别。只是Cookie是放在客户端上的,而Session是记录在服务器上的,数据会更为安全。一般来说,Cookie会带着Session生成的Session id。两者都是用来记录用户的访问状态的。
- Cookie以文本文件格式存储在浏览器中,而session存储在服务端它存储了限制数据量。它只允许4kb它没有在cookie中保存多个变量。
- cookie的存储限制了数据量,只允许4KB,而session是无限量的。
- 我们可以轻松访问cookie值但是我们无法轻松访问会话值,因此它更安全。
- 设置cookie时间可以使cookie过期。但是使用session-destory(),我们将会销毁会话。
总结:如果我们需要经常登录一个站点时,最好用cookie来保存信息,要不然每次登陆都特别麻烦,如果对于需要安全性高的站点以及控制数据的能力时需要用Session效果更佳,当然我们也可以结合两者,使网站按照我们的想法进行运行。
LocalStorage / SessionStorage
因为LocalStorage和SessionStorage在用法和存储时间外的特性上完全一样,后文全用LocalStorage来举例。
我们可以在 Can I use 上查看到,几乎所有主流的浏览器都支持了LocalStorage,IE也从8开始就支持了。
同为客户端存储,LocalStorage有哪些优势。
- 存放大小:一般对于一个网站来说,LocalStorage 可以储存约 5MB 左右的数据,相较于 4KB 的 Cookie 来说,要打上许多。也基本可以满足我们日常网站的需求。
- 存储时间:LocalStorage 是永久储存在客户端上的,没有过期时间。而 SessionStorage 则是在浏览器关闭后销毁的,与不设置
max-age的 Cookie一样。 - 操作简便:LocalStorage 采用
key-value的形式进行存储,并且提供了可以操作的 API,很方便我们查看操作某个属性。
当然,任何技术也有局限性。对于LocalStorage来说,有以下几点:
- 在隐身模式下(或隐私模式下),无法对 LocalStorage 进行操作,值是不可读取的。
key-value存储中的value只能是字符串。因此在存入String类型外的数据时,需要经过转换。尤其是当存入数组或者 JSON 等复杂结构的数据时需要使用JSON.stringify方法,来保证数据的结构不会被破坏。- LocalStorage 的所有操作都是同步的,也就意味着会造成阻塞。因此在数据量大或者处理复杂时,会造成页面卡顿。