我们在之前的章节当中梳理了 浏览器缓存机制 相关内容,乘热打铁,我们本章当中来看看浏览器存储机制的相关内容,主要涉及到 Cookie,localStorage,sessionStorage,Web SQL 和 IndexedDB 相关内容,下面我们就一个一个来进行介绍
Cookie
HTTP Cookie(也叫 Web Cookie 或浏览器 Cookie)是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上,通常它用于告知服务端两个请求是否来自同一浏览器,如保持用户的登录状态,Cookie 主要用于以下三个方面
- 会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息)
- 个性化设置(如用户自定义设置、主题等)
- 浏览器行为跟踪(如跟踪分析用户行为等)
Cookie 的特点
Cookie 的特点有下面这些
Cookie的大小受限,一般为4 KB- 同一个域名下存放
Cookie的个数是有限制的,不同浏览器的个数不一样,一般为20个 Cookie支持设置过期时间,当过期时自动销毁- 每次发起同域下的
HTTP请求时,都会携带当前域名下的Cookie - 支持设置为
HttpOnly,防止Cookie被客户端的JavaScript访问
Cookie 的原理
Cookie 的原理可以如下图所示

第一次访问网站的时候,浏览器发出请求,服务器响应请求后,会在响应头里面添加一个 Set-Cookie 选项,将 Cookie 放入到响应请求中,在浏览器第二次发请求的时候,会通过 Cookie 请求头部将 Cookie 信息发送给服务器,服务端会辨别用户身份,另外 Cookie 的过期时间、域、路径、有效期、适用站点都可以根据需要来指定
Cookie 的设置与获取
下面我们就看看如何使用代码来设置与获取 Cookie,先来看一个最为基本的简单用法
1 | document.cookie = 'name=zhangsan' |
下面的示例主要用于获取名为 test2 的 Cookie
1 | document.cookie = 'test1=Hello' |
Cookie 的缺陷
虽然 Cookie 使用起来很方便,但是它还是存在着一些缺陷,如下
Cookie不够大,Cookie的大小限制在4KB左右Cookie是紧跟域名的,同一个域名下的所有请求,都会携带Cookie,过多的Cookie会带来巨大的性能浪费- 由于在
HTTP请求中的Cookie是明文传递的,所以安全性成问题,除非用HTTPS
Cookie 的安全性
另外我们还需要注意 Cookie 的安全性
| 属性 | 作用 |
|---|---|
value |
如果用于保存用户登录态,应该将该值加密,不能使用明文的用户标识 |
http-only |
不能通过 JavaScript 访问 Cookie,减少 XSS 攻击 |
secure |
只能在协议为 HTTPS 的请求中携带 |
same-site |
规定浏览器不能在跨域请求中携带 Cookie,减少 CSRF 攻击 |
HttpOnly 不支持读写,浏览器不允许脚本操作去更改 Cookie,所以为避免跨域脚本(XSS)攻击,通过 JavaScript 的 document.cookie 无法访问带有 HttpOnly 标记的 Cookie,它们只应该发送给服务端,如果包含服务端 Session 信息的 Cookie 不想被客户端 JavaScript 脚本调用,那么就应该为其设置 HttpOnly 标记,如下
1 | Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2018 07:28:00 GMT; Secure; HttpOnly |
标记为 Secure 的 Cookie 只应通过被 HTTPS 协议加密过的请求发送给服务端,但即便设置了 Secure 标记,敏感信息也不应该通过 Cookie传输,因为 Cookie 有其固有的不安全性,Secure 标记也无法提供确实的安全保障
localStorage
一种持久化的存储方式,也就是说如果不手动清除,数据就永远不会过期,它是采用键值对的方式存储数据,按域名将数据分别保存到对应数据库文件里,相比 Cookie 来说,它能保存更大的数据,localStorage 的特点有以下这些
- 大小限制为
5MB ~ 10MB - 在同源的所有标签页和窗口之间共享数据
- 数据仅保存在客户端,不与服务器进行通信
- 数据持久存在且不会过期,重启浏览器后仍然存在
- 对数据的操作是同步的
具体使用方式如下
1 | // 通过 setItem() 增加一个数据项 |
sessionStorage
与服务端的 Session 类似,sessionStorage 是一种会话级别的缓存,关闭浏览器时数据会被清除,需要注意的是 sessionStorage 的作用域是窗口级别的,也就是说不同窗口之间保存的 sessionStorage 数据是不能共享的,sessionStorage 的特点有以下这些
sessionStorage的数据只存在于当前浏览器的标签页- 数据在页面刷新后依然存在,但在关闭浏览器标签页之后数据就会被清除
- 与
localStorage拥有统一的API接口 - 对数据的操作是同步的
具体使用方式如下
1 | // 通过 setItem() 增加一个数据项 |
Web SQL
Web SQL 数据库 API 实际上不是 HTML5 规范的一部分,而是一个单独的规范,它引入了一组 API 来使用 SQL 来操作客户端数据库
不过需要注意的是,
HTML5已经放弃Web SQL数据库
Web SQL Database 规范中定义的三个核心方法,如下
openDatabase,这个方法使用现有数据库或新建数据库来创建数据库对象transaction,这个方法允许我们根据情况控制事务的提交或回滚executeSql,这个方法用于执行真实的SQL语句
Web SQL 的特点(相比 Cookie 与 WebStorage 而言)
Web SQL能方便进行对象存储Web SQL支持事务,能方便地进行数据查询和数据处理操作
具体使用方式如下
1 | var db = openDatabase('mydb', '1.0', 'Test DB', 2 * 1024 * 1024) |
IndexedDB
IndexedDB 是一种底层 API,用于客户端存储大量结构化数据,包括文件、二进制大型对象,该 API 使用索引来实现对该数据的高性能搜索,虽然 Web Storage 对于存储较少量的数据很有用,但对于存储更大量的结构化数据来说,这种方法不太好用,IndexedDB 提供了一个解决方案,它的特点有以下这些
- 键值对存储,
IndexedDB内部采用对象仓库(Object Store)存放数据,所有类型的数据都可以直接存入,包括JavaScript对象,对象仓库中,数据以键值对的形式保存,每一个数据记录都有对应的主键,主键是独一无二的,不能有重复,否则会抛出一个错误 - 数据操作是异步的,
IndexedDB操作时不会锁死浏览器,用户依然可以进行其他操作,这与LocalStorage形成对比,后者的操作是同步的,异步设计是为了防止大量数据的读写,拖慢网页的表现 - 存储空间大,
IndexedDB的储存空间比LocalStorage大得多,一般来说不少于250MB,甚至没有上限 - 支持二进制存储,
IndexedDB不仅可以储存字符串,还可以储存二进制数据(ArrayBuffer对象和Blob对象) - 同源限制,
IndexedDB受到同源限制,每一个数据库对应创建它的域名,网页只能访问自身域名下的数据库,而不能访问跨域的数据库 - 支持事务型,
IndexedDB支持事务(transaction),这意味着一系列操作步骤之中,只要有一步失败,整个事务就都取消,数据库回滚到事务发生之前的状态,不存在只改写一部分数据的情况
下面我们来看看如何使用
1 | var dbName = 'my_db' |
WebStorage、Cookie 和 IndexedDB 之间的区别
区别如下
| 特性 | Cookie |
localStorage |
sessionStorage |
IndexedDB |
|---|---|---|---|---|
| 数据生命周期 | 一般由服务器生成,可以以设置过期时间 | 除非被清理,否则一直存在 | 页面关闭就清理 | 除非被清理,否则一直存在 |
| 数据存储大小 | 4K |
5M |
5M |
无限 |
| 与服务端通信 | 每次都会携带在 Header 中,对于请求性能影响 |
不参与 | 不参与 | 不参与 |
总结
正是浏览器存储、缓存技术的出现和发展,为我们的前端应用带来了无限的转机,近年来基于存储、缓存技术的第三方库层出不绝,此外还衍生出了 PWA 这样优秀的 Web 应用模型,简单总结一下上文涉及到的几个核心观点
Cookie的本职工作并非本地存储,而是维持状态Web Storage是HTML5专门为浏览器存储而提供的数据存储机制,不与服务端发生通信Web SQL数据库已经被废弃IndexedDB用于客户端存储大量结构化数据
另外除了上文当中所介绍到的一些方式,网上还有一些比较优秀的第三方主流数据库,但是这里就不详细展开了,想了解更多的话可以参考对应链接,列表如下
- localForage,通过使用类似于
localStorage的简单API来使用异步存储(IndexedDB或WebSQL),进而改善你的Web应用程序的离线体验 - PouchDB,一个浏览器内数据库,允许应用程序在本地保存数据,以便用户即使在离线时也可以享受应用程序的所有功能,另外数据在客户端之间是同步的,因此用户可以随时随地保持最新状态
- Rxdb,一个
NoSQL数据库,响应式的设计意味着你不仅可以查询当前状态,还可以订阅所有状态更改 - NeDB,纯
JavaScript实现,不依赖其它库,提供的API是MongoDB API的子集,重要的是它的速度非常快 - Dexie.js,
IndexedDB的包装库,它提供了一套经过精心设计的API,强大的错误处理,较强的可扩展性,此外它能够跟踪数据变化,支持KeyRange(搜索不区分大小写,可设置匹方式和OR操作)