浅谈浏览器存储

浅谈浏览器存储

1、概念

浏览器存储 :浏览器存储是指浏览器提供的一种本地存储数据的机制,包括:CookieWeb StorageIndexedDB 等。

前端持久化存储 :是指通过 JavaScript 在客户端进行数据持久化存储的方式,包括 LocalStorageIndexedDBFile API 等。

表格一览

特性 cookie localStorage sessionStorage indexDB
数据生命周期 一般由服务器生成,可以设置过期时间;前端采用和js-cookie等组件也可以生成 除非被清理,否则一直存在;浏览器关闭还会保存在本地,但是不支持跨浏览器 页面关闭就清理刷新依然存在,不支持跨页面交互 除非被清理,否则一直存在
数据存储大小 4K 5M 5M 不限制大小
与服务端通信 每次都会携带在请求的header 中,对于请求性能有影响;同时由于请求中都带有,所以也容易出现安全问题 不参与 不参与 不参与
特点 字符串键值对在本地存储数据 字符串键值对在本地存储数据 字符串键值对在本地存储数据 IndexedDB 是一个非关系型数据库(不支持通过 SQL 语句操作)。可以存储大量数据,提供接口来查询,还可以建立索引,这些都是其他存储方案无法提供的能力。

2、Cookie

Cookie 最开始被设计出来其实并不是来做本地存储的,而是为了弥补HTTP状态管理上的不足

HTTP 协议是一个无状态协议,客户端向服务器发请求,服务器返回响应,故事就这样结束了,但是下次发请求如何让服务端知道客户端是谁呢?

这种背景下,就产生了 Cookie.

Cookie 本质上就是浏览器里面存储的一个很小的文本文件,内部以键值对的方式来存储(在chrome开发者面板的Application这一栏可以看到)。向同一个域名下发送请求,都会携带相同的 Cookie,服务器拿到 Cookie 进行解析,便能拿到客户端的状态。它可以设置过期时间,用于在客户端和服务器之间传递数据。由于每次请求都会携带 Cookie 信息,可能导致网络开销增加,并且存在安全性问题,故不适合存储大量数据。

Cookie过期等配置

Cookie 分为:Session Cookie 和持久型 CookieCookie 设置中有个 HttpOnly 参数,前端浏览器使用document.cookie 是读取不到 HttpOnly 类型的 Cookie 的,被设置为 HttpOnlyCookie 记录只能通过 HTTP 请求头发送到服务器端进行读写操作,这样就避免了服务器的 Cookie 记录被前端 javascript 修改,保证了服务器验证 Cookie 的安全性。

Cookie 的内容主要包括:名字,值,过期时间,路径和域。路径与域一起构成 Cookie 的作用范围。若不设置过期时间,则表示这个 Cookie 的生命期为浏览器会话期间,关闭浏览器窗口, Cookie 就消失。

这种生命期为浏览器会话期的 Cookie 被称为 会话Cookie会话Cookie 一般不存储在硬盘上而是保存在内存里。若设置了过期时间,浏览器就会把 Cookie 保存到硬盘上,关闭后再次打开浏览器,这些 Cookie 仍然有效直到超过设定的过期时间。存储在硬盘上的 Cookie 可以在不同的浏览器进程间共享,比如两个IE窗口。而对于保存在内存里的 Cookie ,不同的浏览器有不同的处理方式。

操作方式

js 复制代码
// 设置Cookie:
function setCookie(name, value, days) {
  let expires = "";
  if (days) {
    const date = new Date();
    date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
    expires = "; expires=" + date.toUTCString();
  }
  document.cookie = name + "=" + value + expires + "; path=/";
}


// 读取Cookie
function getCookie(name) {
  const nameEQ = name + "=";
  const ca = document.cookie.split(';');
  for (let i = 0; i < ca.length; i++) {
    let c = ca[i];
    while (c.charAt(0) === ' ') {
      c = c.substring(1, c.length);
    }
    if (c.indexOf(nameEQ) === 0) {
      return c.substring(nameEQ.length, c.length);
    }
  }
  return null;
}

// 删除Cookie
function deleteCookie(name) {
  setCookie(name, "", -1);
}

// 使用
// 设置Cookie,有效期为7天
setCookie("username", "john_doe", 7);
console.log(cookie); // "username=john_doe; expires=Fri, 04 Aug 2023 14:47:16 GMT; path=/"

// 读取Cookie
const username = getCookie("username");
console.log(username); // "john_doe"

// 删除Cookie
deleteCookie("username");

Cookie 的作用很好理解,就是用来做状态存储的,但它也是有诸多致命的缺陷的:

  • 容量缺陷。Cookie 的体积上限只有4KB,只能用来存储少量的信息。
  • 性能缺陷。Cookie 紧跟域名,不管域名下面的某一个地址需不需要这个 Cookie ,请求都会携带上完整的 Cookie,这样随着请求数的增多,其实会造成巨大的性能浪费的,因为请求携带了很多不必要的内容。
  • 安全缺陷。由于 Cookie 以纯文本的形式在浏览器和服务器中传递,很容易被非法用户截获,然后进行一系列的篡改,在 Cookie 的有效期内重新发送给服务器,这是相当危险的。另外,在HttpOnlyfalse 的情况下,Cookie 信息能直接通过 JS 脚本来读取。

3、Session

session 机制是一种服务器端的机制,服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。当程序需要为某个客户端的请求创建一个session 时,服务器首先检查这个客户端的请求里是否已包含了一个session 标识(称为 session ID),如果已包含则说明以前已经为此客户端创建过 session,服务器就按照 session ID 把这个session 检索出来使用(检索不到,会新建一个),如果客户端请求不包含 session ID,则为此客户端创建一个session 并且生成一个与此session 相关联的 session IDsession ID 的值应该是一个既不会重复,又不容易被找到规律以仿造的字符串,这个 session ID 将被在本次响应中返回给客户端保存。

总结

  • 服务器端存储session 是服务器端的一种机制,用于在服务端存储用户会话数据。服务器会为每个用户创建一个唯一的 session,并在客户端保存一个对应的 session ID
  • 生命周期session 的生命周期由服务器管理,可以设置 session 的过期时间,当用户长时间不活动或超过过期时间时,session 会被销毁。

Cookie 和 Session 比较

  • cookie 数据存放在客户的浏览器上,session 数据放在服务器上。
  • cookie 不是很安全,别人可以分析存放在本地的 cookie 并进行 cookie 欺骗
  • session 会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能
  • 单个 cookie 保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个 cookie
  • 个人建议:将登录信息等重要信息存放在 session 中,其他信息如果需要在每个请求中携带,可以放在 cookie 中,剩下的信息本地化缓在 Web Storage 中。

4、Web Storage

Web Storage 包括 localStoragesessionStorage,是 HTML5 新增的浏览器存储机制。它们在浏览器端存储数据,不会随着每次请求发送到服务器,所以不会增加网络开销。localStorage 存储的数据没有过期时间,除非用户手动清除或网站清除,否则数据会一直存在。sessionStorage 的数据在用户关闭浏览器或页面后会被清除,适用于临时性数据存储。

4.1、localStorage

localStorage 有一点跟 Cookie 一样,就是针对一个域名,即在同一个域名下,会存储相同的一段。它可以存储较大量的数据,数据不会过期,一直保留在客户端。由于数据保存在客户端,所以不会增加服务器负担。单个 localStorage 的大小受限,可以用多个 iframe 方式使用多个域名来突破单个页面下 localStorage 存储数据的最大限制。

特别说明:浏览器多个标签页打开同个域名时,localStorage 内容一般是共享的。其位置这可以监听事件 storage 来做一致性操作响应处理。这样会导致如下现象:

标签页一:通过某行为修改 localStorage 中某个属性值,然后数据接口依赖该属性值;

标签页二:由于 localStorage 标签页间共享,导致标签页二数据不准确!

操作方式

接下来我们来具体看看如何来操作 localStorage

js 复制代码
let obj = { name: "sanyuan", age: 18 };

localStorage.setItem("name", "sanyuan"); 
localStorage.setItem("info", JSON.stringify(obj));

接着进入相同的域名时就能拿到相应的值:

js 复制代码
let name = localStorage.getItem("name"); 
let info = JSON.parse(localStorage.getItem("info"));

从这里可以看出,localStorage 其实存储的都是字符串,如果是存储对象需要调用 JSON.stringify 方法,并且用 JSON.parse 来解析成对象。

应用场景

利用 localStorage 的较大容量和持久特性,可以利用 localStorage 存储一些内容稳定的资源,比如官网的 logo,或者存储 Base64 格式的图片资源等。

Cookie 和 localStorage 比较

  • localStorage 的容量上限为 5M,相比于Cookie4K 大大增加。当然这个 5M 是针对一个域名的,因此对于一个域名是持久存储的。
  • 只存在客户端,默认不参与与服务端的通信。这样就很好地避免了 Cookie 带来的性能问题安全问题
  • 接口封装。通过 localStorage 暴露在全局,并通过它的 setItemgetItem 等方法进行操作,非常方便。

4.2、sessionStorage

sessionStoragelocalStoragecookie 都是在浏览器端存储的数据,其中 sessionStorage 的概念很特别,引入了一个"浏览器窗口"的概念。sessionStorage 是在同源的同窗口(或tab)中,始终存在的数据。也就是说只要这个浏览器窗口没有关闭,即使刷新页面或进入同源另一页面,数据仍然存在。关闭窗口后,sessionStorage 即被销毁。同时"独立"打开的不同窗口,即使是同一页面,sessionStorage 对象也是不同的。

临时存储

很多时候数据只需要在用户浏览一组页面期间使用,关闭窗口后数据就可以丢弃了,这种情况使用 sessionStorage 非常方便。

sessionStorage 以下方面和 localStorage 一致:

  • 容量。容量上限也为 5M。
  • 只存在客户端,默认不参与与服务端的通信。
  • 接口封装。除了sessionStorage名字有所变化,存储方式、操作方式均和localStorage一样。

sessionStoragelocalStorage 有一个本质的区别,那就是前者只是 会话级别的存储 ,并不是 持久化存储 。会话结束,也就是页面关闭,这部分 sessionStorage 就不复存在了。

操作方式

接下来我们来具体看看如何来操作 sessionStorage

js 复制代码
//存储
sessionStorage.setItem("name", "sanyuan"); 

//取出
sessionStorage.getItem("name");

//清除 
sessionStroage.clear();

应用场景

  • 可以用它对表单信息进行维护,将表单信息存储在里面,可以保证页面即使刷新也不会让之前的表单信息丢失。
  • 可以用它存储本次浏览记录。如果关闭页面后不需要这些记录,用 sessionStorage 就再合适不过了。事实上微博就采取了这样的存储方式。

5、IndexedDB

IndexedDB 是运行在浏览器中的非关系型数据库,为大型数据的存储提供了接口。 本质上是数据库,绝不是和刚才 WebStorage5M 一个量级,理论上这个容量是没有上限的。

关于它的使用,本文侧重原理,而且 MDN 上的教程文档已经非常详尽,这里就不做赘述了,感兴趣可以看一下使用文档

IndexedDB的存储空间(所有访问的网站总和)为磁盘可用空间的50%,或根据浏览器的设定分配;

接着我们来分析一下 IndexedDB 的一些重要特性,除了拥有数据库本身的特性,比如支持事务存储二进制数据,还有这样一些特性需要格外注意:

  • 键值对存储。内部采用对象仓库存放数据,在这个对象仓库中数据采用键值对的方式来存储。
  • 异步操作。数据库的读写属于 I/O 操作, 浏览器中对异步 I/O 提供了支持。
  • 受同源策略限制,即无法访问跨域的数据库。
  • 它是 NoSQL 的,不需要我们去写一些特定的 SQL 语句来对数据库进行操作,数据形式使用的 json
  • 一个数据库中可以包含多种对象集合,相对于 SQL 数据库来说就是多个表;在一个域(名)下,还可以有多个数据库。但是不能跨域访问别的域名之下的数据库。

另外一方面,用 localStorage 只能保存字符串,如果是其他的类型,那就必须用 JSON.stringify 来转换为字符串后再保存,而 IndexedDB 则可以直接保存。此外,还具备一般 DBMS 的常用功能,例如遍历、筛选等。

indexedDB出现的意义

  • 前端存储,已经有了 localStorageCookies ,但是它们都是比较简单的技术。而 IndexedDB 提供了类似数据库风格的数据储存和使用方式。
  • Cookies 只能是字符串,储存空间有限,每次 HTTP 接受和发送都会传递 Cookies 数据,它会占用额外的流量。
  • localStorage 是用 key-value 键值模式储存数据,想让 localstorage 存储对象,你需要借助 JSON.stringify() 能将对象变成字符串形式,再用 JSON.parse() 将字符串还原成对象,当存储的数据庞大时,这就不是最佳的方案了,localstorage 就是专门为小数量数据设计的,它的 api 设计为同步的。
  • IndexedDB 很适合存储大量数据,它的 API 是异步调用的,IndexedDB 使用索引存储数据,各种数据库操作放在事务中执行,IndexedDB 支持简单的数据类型,它比 localstorage 强大,API 也相对复杂,对于简单的数据,还是使用 localstorage
  • IndexedDB 能提供更为复杂的查询数据的方式。

IndexedDB特点

  • 非关系型数据库(NoSql) :我们都知道 MySQL 等数据库都是关系型数据库,它们的主要特点就是数据都以一张二维表的形式存储,而 IndexedDB 是非关系型数据库,主要以键值对的形式存储数据。
  • 持久化存储cookielocalStoragesessionStorage 等方式存储的数据当我们清楚浏览器缓存后,这些数据都会被清除掉的,而使用 IndexedDB 存储的数据则不会,除非手动删除该数据库。
  • 异步操作IndexedDB 操作时不会锁死浏览器,用户依然可以进行其他的操作,这与 localstorage 形成鲜明的对比,后者是同步的。
  • 支持事务IndexedDB 支持事务(transaction),这意味着一系列的操作步骤之中,只要有一步失败了,整个事务都会取消,数据库回滚的事务发生之前的状态,这和 MySQL 等数据库的事务类似。
  • 同源策略IndexedDB 同样存在同源限制,每个数据库对应创建它的域名。网页只能访问自身域名下的数据库,而不能访问跨域的数据库。
  • 存储容量大 :这也是 IndexedDB 最显著的特点之一了,这也是不用 localStorage 等存储方式的最好理由。

操作方式

js 复制代码
/**
 * 打开数据库
 * @param {object} dbName 数据库的名字
 * @param {string} storeName 仓库名称
 * @param {string} version 数据库的版本
 * @return {object} 该函数会返回一个数据库实例
 */
function openDB(dbName, version = 1) {
  return new Promise((resolve, reject) => {
    //  兼容浏览器
    var indexedDB =
      window.indexedDB ||
      window.mozIndexedDB ||
      window.webkitIndexedDB ||
      window.msIndexedDB;
    let db;
    // 打开数据库,若没有则会创建
    const request = indexedDB.open(dbName, version);
    // 数据库打开成功回调
    request.onsuccess = function (event) {
      db = event.target.result; // 数据库对象
      console.log("数据库打开成功");
      resolve(db);
    };
    // 数据库打开失败的回调
    request.onerror = function (event) {
      console.log("数据库打开报错");
    };
    // 数据库有更新时候的回调
    request.onupgradeneeded = function (event) {
      // 数据库创建或升级的时候会触发
      console.log("onupgradeneeded");
      db = event.target.result; // 数据库对象
      var objectStore;
      // 创建存储库
      objectStore = db.createObjectStore("signalChat", {
        keyPath: "sequenceId", // 这是主键
        // autoIncrement: true // 实现自增
      });
      // 创建索引,在后面查询数据的时候可以根据索引查
      objectStore.createIndex("link", "link", { unique: false }); 
      objectStore.createIndex("sequenceId", "sequenceId", { unique: false });
      objectStore.createIndex("messageType", "messageType", {
        unique: false,
      });
    };
  });
}
......

我们将创建数据库的操作封装成了一个函数,并且该函数返回一个 promise 对象,使得在调用的时候可以链式调用,函数主要接收两个参数:数据库名称、数据库版本。函数内部主要有三个回调函数,分别是:

  • onsuccess:数据库打开成功或者创建成功后的回调,这里我们将数据库实例返回了出去。
  • onerror:数据库打开或创建失败后的回调。
  • onupgradeneeded:当数据库版本有变化的时候会执行该函数,比如我们想创建新的存储库(表),就可以在该函数里面操作,更新数据库版本即可。

应用场景

  • IndexedDB 是异步操作的,适合存储大量数据或需要离线访问的应用。
  • 数据可视化等界面,大量数据,每次请求会消耗很大性能。
  • 即时聊天工具,大量消息需要存在本地。
  • 其它存储方式容量不满足时,不得已使用 IndexedDB

6、其他存储

  • WebSQL:二维表的形成存储大量数据到客户端,但目前只有 Chrome 浏览器有。
  • Application Cache:通过 manifest 配置文件在本地有选择性地存储 javascriptcss、图片等静态资源文件的文件缓存机制,已废弃。
  • cacheStorage:在 ServiceWorker 规范中定义的,用于保存每个 ServiceWorker声明的 Cache 对象,未来可能替代 Application Cache 的离线方案。
  • Flash缓存:主要基于 Flash,具有读写浏览器本地目录的功能。
  • File APIFile API 允许前端通过 JavaScript 读取和操作用户的本地文件。可以实现将文件存储在客户端,并在需要时读取和处理文件数据。

7、区别

  1. localStorage
  • 存储容量较大localStorage 可以存储较大量的数据,通常可以存储 5MB 的数据。
  • 持久性localStorage 中的数据不会过期,除非用户手动清除或网站清除,否则数据会一直保留在客户端。
  • 作用域localStorage 的作用域是整个域名,即在同一个域名下的所有页面都可以访问同一份 localStorage 数据。
  1. sessionStorage
  • 存储容量较大 :与 localStorage 一样,通常可以存储 5MB 的数据。
  • 会话级别sessionStorage 中的数据在当前会话期间有效,即在用户关闭当前浏览器窗口或标签页后,数据会被清除。
  • 作用域sessionStorage 的作用域是当前窗口或标签页,不同窗口或标签页之间无法共享数据。
  1. session
  • 服务器端存储session 是服务器端的一种机制,用于在服务端存储用户会话数据。服务器会为每个用户创建一个唯一的 session,并在客户端保存一个对应的 session ID
  • 生命周期session 的生命周期由服务器管理,可以设置 session 的过期时间,当用户长时间不活动或超过过期时间时, session 会被销毁。
  1. cookies
  • 存储容量小cookies 的存储容量较小,一般限制在 4KB 左右。
  • 持久性 :可以设置 cookies 的过期时间,可以是会话级的,也可以是持久性的。当设置了过期时间,cookies 会在过期后被删除。
  • 作用域cookies 的作用域是整个域名,与 localStorage 类似,在同一个域名下的所有页面都可以访问相同的 cookies 数据。
  1. IndexedDB
  • 存储容量大IndexedDB 是一种数据库,可以存储较大量的结构化数据,一般可以存储几十MB甚至几百MB的数据。
  • 异步操作IndexedDB 是异步的,操作数据时需要使用异步API 进行处理。
  • 丰富的查询功能IndexedDB 支持复杂的数据查询和索引,可以高效地检索和处理大量数据。

8、总结

  • localStoragesessionStorageHTML5 新增的浏览器存储机制,用于在客户端存储数据。
  • session 是服务器端的存储机制,用于在服务端存储用户会话数据。
  • cookies 是在客户端和服务端都可以操作的存储机制,用于存储少量数据。它可以设置过期时间,可以用于跟踪用户状态和实现记住登录功能。
  • localStoragesessionStoragesessioncookies 是浏览器端的存储机制,用于在客户端存储数据,容量和持久性各有不同。
  • IndexedDB 是一种高级的浏览器端数据库,适用于需要存储大量结构化数据并进行复杂查询的场景。它与其他浏览器存储方式相比,存储容量更大且查询效率更高,但使用起来相对复杂一些,需要异步操作。
相关推荐
Wect3 天前
浏览器缓存机制
前端·面试·浏览器
FliPPeDround7 天前
浏览器扩展 E2E 测试的救星:vitest-environment-web-ext 让你告别繁琐配置
e2e·浏览器·测试
SuperEugene7 天前
浏览器存储:localStorage / sessionStorage / cookie 应该怎么用
前端·javascript·面试·浏览器
宁雨桥7 天前
浏览器渲染原理
前端·浏览器·原理
YZ0999 天前
2026年如何批量保存小红书作者主页的视频、图片和文案?
经验分享·浏览器·插件
程序员ys9 天前
网页白屏的原理与优化
前端·性能优化·浏览器
Wect11 天前
从输入URL到页面显示的完整技术流程
前端·面试·浏览器
NEXT0611 天前
从输入 URL 到页面展示的完整链路解析
网络协议·面试·浏览器
CappuccinoRose14 天前
CSS 语法学习文档(十五)
前端·学习·重构·渲染·浏览器
REDcker15 天前
Media Source Extensions (MSE) 详解
前端·网络·chrome·浏览器·web·js