# 浏览器本地存储
近年来,随着浏览器存储技术的提升,出现了多种前端存储方式。比如:cookie
、localStorage
、sessionStorage
、Web SQL
、indexedDB
。 对于前三种方式想必大家耳熟能详,因为 cookie、localStorage、sessionStorage 都属于 js 语言的本地存储,而 Web SQL 和 indexedDB 则是一种前端存储数据库。 这篇文章会分别介绍这五种存储方式,以及他们之间的差异及优缺点。
# 一、Cookie
# 🍪 什么是 Cookie
Cookie
是最早被提出来的本地存储⽅式,在此之前,服务端是⽆法判断⽹络中的两个请求是否是同⼀⽤户发起的,也就是无法辨别用户身份,为解决这个问题,Cookie 就出现了。Cookie 的⼤⼩只有 4kb,它是⼀种纯⽂本⽂件,每次发起 HTTP 请求都会携带 Cookie。
Cookie
主要用于以下三个方面:
- 会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息)
- 个性化设置(如用户自定义设置、主题等)
- 浏览器行为跟踪(如跟踪分析用户行为等)
# 📥 Cookie 的存储
Cookie
总是保存在客户端中,按在客户端中的存储位置,Cookie 可以分为内存 Cookie 和硬盘 Cookie
内存Cookie
由浏览器进行维护,保存在内存中,浏览器关闭时 Cookie 就会消失,其存在时间是短暂的。硬盘Cookie
保存在硬盘中,有一个过期时限,用户手动清除或者过期时间到了,才会被清除。
如何判断一个 cookie 是内存 cookie 还是硬盘 cookie?
- 没有设置过期时间,默认情况下 cookie 是内存 cookie,在关闭浏览器时会自动清除。
- 有设置过期时间,并且过期时间不为 0 或者负数的 cookie,时硬盘 cookie,需要手动或者到期,才会删除。


# ✨ Cookie 的特性
- Cookie 一旦创建成功,
名称就无法修改
- Cookie 的
大小受限
,一般为 4kb,同一个域名下存放的 Cookie个数有限
- Cookie
无法进行跨域
,也就是说 a 域名和 b 域名下的 cookie 时无法共享的,这是由 Cookie 的隐私安全性决定的,这样就能够阻止非法获取其他网站的 Cookie - 每次发起同域下的 HTTP 请求,都会携带当前域名下的 Cookie
- 支持设置
HttpOnly
,防止 Cookie 被客户端的 JavaScript 访问
# 💫 Cookie 的原理

第一次访问网站的时候,浏览器发出请求,服务器响应请求后,会在响应头里面添加一个 Set-Cookie
选项,将 Cookie
放入到响应请求中,在浏览器第二次发请求的时候,会通过 Cookie
请求头部将 Cookie
信息发送给服务器,服务端会辨别用户身份,另外 Cookie
的过期时间、域、路径、有效期、适用站点都可以根据需要来指定。
# 🌟 Cookie 其字段及作用
字段名 | 作用 |
---|---|
Name | cookie 的名称 |
Value | cookie 的值,对于认证 cookie,value 值包括 web 服务器所提供的访问令牌; |
Size | cookie 的⼤⼩ |
Path | 访问此 cookie 的⻚⾯路径 |
Secure | 指定是否使⽤ HTTPS 安全协议发送 Cookie |
Domain | 可以访问该 cookie 的域名,Cookie 机制并未遵循严格的同源策略,允许⼀个⼦域可以设置或获取其⽗域的 Cookie。 |
HTTPOnly | 规定了这个 cookie 只能被服务器访问,不能使⽤ js 脚本访问 |
Expires/Max-size | 设置 cookie 的超时时间。不设置的话默认值是 Session,意思是 cookie 会和 session ⼀起失效。当浏览器关闭(不是浏览器标签⻚,⽽是整个浏览器) 后,此 cookie 失效。 |
# 🌈 Cookie 的使用
# 创建 Cookie
document.cookie = "username=langyixuan;"; // 创建一个名为username的cookie
document.cookie = "expires=Thu, 18 Dec 2043 12:00:00 GMT;"; // 设置cookie的有效日期
# 读取 Cookie
var x = document.cookie;
# 删除 Cookie
删除 Cookie 非常简单,只需要设置expires
参数为以前的时间即可,删除时不必指定 Cookie 的值。
document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 GMT";
# 封装函数
// 添加cookie
function setCookie(key, value, iDay) {
var oDate = new Date();
oDate.setDate(oDate.getDate() + iDay);
document.cookie = key + "=" + value + ";expires=" + oDate;
}
// 删除cookie
function removeCookie(key) {
setCookie(key, "", -1); //这里只需要把Cookie保质期退回一天便可以删除
}
// 获取cookie
function getCookie(key) {
var cookieArr = document.cookie.split("; ");
for (var i = 0; i < cookieArr.length; i++) {
var arr = cookieArr[i].split("=");
if (arr[0] === key) {
return arr[1];
}
}
return false;
}
# 😑 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
标记,如下:
Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2018 07:28:00 GMT; Secure; HttpOnly
标记为 Secure
的 Cookie
只应通过被 HTTPS
协议加密过的请求发送给服务端,但即便设置了 Secure
标记,敏感信息也不应该通过 Cookie
传输,因为 Cookie
有其固有的不安全性,Secure
标记也无法提供确实的安全保障。
# 二、LocalStorage 和 SessionStorage
LocalStorage与SessionStorage
是 HTML5 新引⼊的特性,用于进行本地存储。由于有的时候我们存储的信息较⼤,Cookie 就不能满⾜我们的需求,这时候LocalStorage和SessionStorage
就派上⽤场了。
LocalStorage 与 SessionStorage 两者的使用非常相似,只是在存储时效上有差异。
# 💙 LocalStorage
一种 持久化的存储方式 ,也就是说如果不手动清除,数据就永远不会过期,它是采用键值对的方式存储数据,按域名将数据分别保存到对应数据库文件里,相比 Cookie
来说,它能保存更大的数据。
👉 LocalStorage 的特点有以下:
- 大小限制为
5MB ~ 10MB
- 在同源的所有标签页和窗口之间共享数据
- 数据仅保存在客户端,不与服务器进行通信
- 数据持久存在且不会过期,重启浏览器后仍然存在
- 对数据的操作是同步的
👉 LocalStorage 的优点:
- 在⼤⼩⽅⾯,LocalStorage 的⼤⼩⼀般为 5MB,可以储存更多的信息
- LocalStorage 是持久储存,并不会随着⻚⾯的关闭⽽消失,除⾮主动清理,不然会永久存在
- 仅储存在本地,不像 Cookie 那样每次 HTTP 请求都会被携带
👉 LocalStorage 的缺点:
- 存在浏览器兼容问题,IE8 以下版本的浏览器不⽀持
- 如果浏览器设置为隐私模式,那我们将⽆法读取到 LocalStorage
- LocalStorage 受到同源策略的限制,即端⼝、协议、主机地址有任何⼀个不相同,都不会访问
👉 LocalStorage 具体使用:
// 通过 setItem() 增加一个数据项
localStorage.setItem("myName", "zhangsan");
// 通过 getItem() 获取某个数据项
let me = localStorage.getItem("myName");
// 通过 removeItem() 移除某个数据项
localStorage.removeItem("myName");
// 移除所有数据项
localStorage.clear();
👉 LocalStorage 的使用场景:
- 有些⽹站有换肤的功能,这时候就可以将换肤的信息存储在本地的 LocalStorage 中,当需要换肤的时候,直接操作 LocalStorage 即可
- 在⽹站中的⽤户浏览信息也会存储在 LocalStorage 中,还有⽹站的⼀些不常变动的个⼈信息等也可以存储在本地的 LocalStorage 中
# 💚 SessionStorage
SessionStorage 和 LocalStorage 都是在 HTML5 才提出来的存储⽅案,SessionStorage
主要⽤于 临时保存 同⼀窗⼝(或标签⻚)的数据,刷新⻚⾯时不会删除,关闭窗⼝或标签⻚之后将会删除这些数据。
👉 SessionStorage 的特点有以下:
sessionStorage
的数据只存在于当前浏览器的标签页- 数据在页面刷新后依然存在,但在关闭浏览器标签页之后数据就会被清除
- 与
localStorage
拥有统一的API
接口 - 对数据的操作是同步的
👉 SessionStorage 与 LocalStorage 对⽐:
- SessionStorage 和 LocalStorage 都在
本地进⾏数据存储
- SessionStorage 也有
同源策略的限制
,但是 SessionStorage 有⼀条更加严格的限制, SessionStorage 只有在同⼀浏览器的同⼀窗⼝下才能够共享 - LocalStorage 和 SessionStorage 都
不能被爬⾍爬取
👉 SessionStorage 具体使用:
// 通过 setItem() 增加一个数据项
sessionStorage.setItem("myName", "zhangsan");
// 通过 getItem() 获取某个数据项
let me = sessionStorage.getItem("myName");
// 通过 removeItem() 移除某个数据项
sessionStorage.removeItem("myName");
// 移除所有数据项
sessionStorage.clear();
👉 SessionStorage 的使用场景:
- 由于 SessionStorage
具有时效性
,所以可以⽤来存储⼀些⽹站的游客登录的信息,还有临时的浏览记录的信息。当关闭⽹站之后,这些信息也就随之消除了。
# 三、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
支持事务,能方便地进行数据查询和数据处理操作
👉 具体使用方式如下
var db = openDatabase("mydb", "1.0", "Test DB", 2 * 1024 * 1024);
db.transaction(function(tx) {
// 执行查询操作
tx.executeSql("CREATE TABLE IF NOT EXISTS LOGS (id unique, log)");
// 执行插入操作
tx.executeSql('INSERT INTO LOGS (id, log) VALUES (1, "foobar")');
tx.executeSql('INSERT INTO LOGS (id, log) VALUES (2, "logmsg")');
});
# 四、IndexedDB
👉 详细内容可参考 浏览器数据库 IndexedDB 入门教程
现有的浏览器数据储存方案,都不适合储存大量数据:Cookie 的大小不超过 4KB,且每次请求都会发送回服务器;LocalStorage 在 2.5MB 到 10MB 之间(各家浏览器不同),而且不提供搜索功能,不能建立自定义的索引。所以,需要一种新的解决方案,这就是 IndexedDB 诞生的背景。
IndexedDB
是一种底层 API
,用于客户端存储大量结构化数据,包括文件、二进制大型对象,该 API
使用索引来实现对该数据的高性能搜索。
👉 它的特点有以下这些:
- 键值对存储,
IndexedDB
内部采用对象仓库(Object Store
)存放数据,所有类型的数据都可以直接存入,包括JavaScript
对象,对象仓库中,数据以键值对的形式保存,每一个数据记录都有对应的主键,主键是独一无二的,不能有重复,否则会抛出一个错误 - 数据操作是异步的,
IndexedDB
操作时不会锁死浏览器,用户依然可以进行其他操作,这与LocalStorage
形成对比,后者的操作是同步的,异步设计是为了防止大量数据的读写,拖慢网页的表现 - 存储空间大,
IndexedDB
的储存空间比LocalStorage
大得多,一般来说不少于250MB
,甚至没有上限 - 支持二进制存储,
IndexedDB
不仅可以储存字符串,还可以储存二进制数据(ArrayBuffer
对象和Blob
对象) - 同源限制,
IndexedDB
受到同源限制,每一个数据库对应创建它的域名,网页只能访问自身域名下的数据库,而不能访问跨域的数据库 - 支持事务型,
IndexedDB
支持事务(transaction
),这意味着一系列操作步骤之中,只要有一步失败,整个事务就都取消,数据库回滚到事务发生之前的状态,不存在只改写一部分数据的情况
👉 indexedDB 的基本使用:
var dbName = "my_db";
var request = indexedDB.open(dbName, 2);
request.onerror = function(event) {
// 错误处理
};
request.onupgradeneeded = function(event) {
var db = event.target.result;
// 建立一个对象仓库来存储我们客户的相关信息,我们选择 ssn 作为键路径(key path),因为 ssn 可以保证是不重复的
var objectStore = db.createObjectStore("customers", { keyPath: "ssn" });
// 建立一个索引来通过姓名来搜索客户,名字可能会重复,所以我们不能使用 unique 索引
objectStore.createIndex("name", "name", { unique: false });
// 使用邮箱建立索引,我们确保客户的邮箱不会重复,所以我们使用 unique 索引
objectStore.createIndex("email", "email", { unique: true });
// 使用事务的 oncomplete 事件确保在插入数据前对象仓库已经创建完毕
objectStore.transaction.oncomplete = function(event) {
// 将数据保存到新创建的对象仓库
var customerObjectStore = db
.transaction("customers", "readwrite")
.objectStore("customers");
customerData.forEach(function(customer) {
customerObjectStore.add(customer);
});
};
};
# 总结
该篇文章主要梳理了浏览器本地存储的五种方案的使用,分别是Cookie
、LocalStorage
、SessionStorage
、Web SQL
、IndexedDB
。