浏览器之客户端存储

本文涉及的产品
对象存储 OSS,20GB 3个月
对象存储 OSS,恶意文件检测 1000次 1年
对象存储 OSS,内容安全 1000次 1年
简介: 1. cookie2. Web Storagea. sessionStorageb. localStorage3. IndexDB


古希腊人在阿波罗神庙柱子上刻了一句箴言:认识你自

前言

大家好,我是柒八九。我们在网络拾遗之Http缓存文章中,从网络协议的视角介绍了网站客户端缓存 中的HTTP缓存策略,并对强缓存协商缓存做了较为详细的介绍。

而今天,这篇文章,打算介绍客户端缓存的另外一种类别 -- 本地缓存(也可以叫客户端存储)

还是老样子。赶紧上车。发车走起。

::: block-2

面试加油站

  1. 存储在客户端上的cookie
    1. 每个 cookie 不超过 4 KB
    2. 每个域不超过 20 个 cookie
  2. Web Storage 的目的是解决通过客户端存储不需要频繁发送回服务器的数据时使用 cookie 的问题
  3. Web Storage 定义了两个对象localStoragesessionStorage
    1. localStorage永久存储机制
    2. sessionStorage跨会话的存储机制
    3. 单个域的大小为5M
  4. IndexedDB 是一个事务型数据库系统 :::

文章概要

  1. cookie
  2. Web Storage
  1. sessionStorage
  2. localStorage
  1. IndexDB

1. cookie

HTTP cookie 通常也叫作 cookie,最初用于在客户端存储会话信息

这个规范要求服务器响应 HTTP 请求时,通过发送 Set-Cookie HTTP 头部包含会话信息。

例如,下面是包含这个头部的一个 HTTP响应

HTTP/1.1 200 OK
Content-type: text/html
+ Set-Cookie: name=value
Other-header: other-header-value
复制代码

这个 HTTP 响应会设置一个为"name",为"value"的 cookie。名和值在发送时都会经过 URL 编码

浏览器会存储这些会话信息,并在之后的每个请求中都会通过 HTTP 头部 cookie 再将它们发回服务器

GET /index.js HTTP/1.1
+ Cookie: name=value
Other-header: other-header-value 
复制代码

限制

cookie 是与特定域绑定的

设置 cookie 后,它会与请求一起发送到创建它的域,这样能够保证 cookie 中存储的信息只对被认可的接收者开放,不被其他域访问。

cookie 存储在客户端机器上,所以有很多针对安全性的限制

  • 不超过 300 个 cookie
  • 每个 cookie 不超过 4 KB
  • 每个域不超过 20 个 cookie
  • 每个域不超过  80KB

不同浏览器的针对每个域能设置多少cookie有不同的限制

如果 cookie 总数超过了单个域的上限,浏览器就会删除之前设置的 cookie

如果创建的 cookie 超过最大限制,则该 cookie 会被静默删除

cookie 的构成

cookie 在浏览器中是由以下参数构成的

  • 名称
    1. 唯一标识cookie 的名称
    2.不区分大小写
    3. 必须经过 URL 编码

  • 1. 存储在 cookie 里的字符串值
    2. 必须经过 URL 编码

  • 1. cookie 有效的域
    2. 发送到这个域的所有请求都会包含对应的 cookie
  • 过期时间
    1. 表示何时删除cookie时间戳
    2. 默认情况下,浏览器会话结束后会删除所有 cookie
    3.这个值是 GMT 格式(Wdy, DD-Mon-YYYY HH:MM:SS GMT),用于指定删除 cookie 的具体时间
    4.把过期时间设置为过去的时间会立即删除 cookie
  • 路径
    1. 请求 URL包含这个路径才会把 cookie 发送到服务器
  • 安全标志
    1. 设置之后,只在使用 SSL 安全连接的情况下才会把 cookie 发送到服务器

这些参数在 Set-Cookie 头部中使用分号加空格隔开

HTTP/1.1 200 OK
Content-type: text/html
+ Set-Cookie: name=value; expires=expiration_time; 
+ path=domain_path; domain=domain_name; secure
Other-header: other-header-value
复制代码

安全标志secure 是 cookie 中唯一的非名/值对,只需一个 secure 就可以了


JS 中的 cookie

在 JS 中只有 BOMdocument.cookie 属性用于处理 cookie

document.cookie 返回包含页面中所有有效cookie 的字符串(根据域、路径、过期时间和安全设置),以分号分隔。

所有名和值都是 URL 编码的,因此必须使用 decodeURIComponent()解码。

设置值时,可以通过 document.cookie 属性设置新的cookie 字符串。这个字符串在被解析后会添加到原有 cookie

设置 document.cookie 不会覆盖之前存在的任何 cookie,除非设置了已有的cookie

设置cookie 的格式如下,与 Set-Cookie 头部的格式一样:

name=value; expires=expiration_time; 
path=domain_path; domain=domain_name; secure
复制代码

在所有这些参数中,只有 cookie 的名称和值是必需

下面是个简单的例子:

document.cookie =  encodeURIComponent("name") + "=" +
                   encodeURIComponent("Nicholas");
复制代码

创建一个名为name,值为bcnz789会话 cookie,这个 cookie 在每次客户端向服务器发送请求时都会被带上,在浏览器关闭时就会被删除

子 cookie

为绕过浏览器对每个域 cookie 数的限制,有些开发者提出了子 cookie的概念。

子 cookie 是在单个 cookie 存储的小块数据,本质上是使用 cookie 的值单个 cookie 中存储多个名/值对

name=name1=value1&name2=value2&name3=value3&name4=value4&name5=value5
复制代码

注意事项

有一种叫作 HTTP-onlycookieHTTP-only 可以在浏览器设置,也可以在服务器设置,但只能在服务器上读取,这是因为 JS 无法取得这种 cookie 的值

因为所有 cookie 都会作为请求头部由浏览器发送给服务器,所以在 cookie 中保存大量信息可能会影响特定域浏览器请求的性能。保存的 cookie 越大,请求完成的时间就越长。即使浏览器对 cookie 大小有限制,最好还是尽可能只通过 cookie 保存必要信息,以避免性能问题。


Web Storage

Web Storage 的目的是解决通过客户端存储不需要频繁发送回服务器的数据时使用 cookie 的问题

Web Storage 规范最新的版本是第 2 版,这一版规范主要有两个目标

  1. 提供cookie 之外存储会话数据的途径
  2. 提供跨会话持久化存储大量数据的机制

Web Storage 的第 2 版定义了两个对象localStoragesessionStorage

  • localStorage永久存储机制
  • sessionStorage跨会话的存储机制

这两种浏览器存储 API 提供了在浏览器中不受页面刷新影响而存储数据的两种方式。

Storage 类型

Storage 类型用于保存名/值对数据,直至存储空间上限(由浏览器决定)。

Storage 的实例增加了以下方法

  • clear():删除所有值
  • getItem(name):取得给定 name 的值。
  • key(index):取得给定数值位置的名称。
  • removeItem(name):删除给定 name 的名/值对。
  • setItem(name, value):设置给定 name 的值。

通过 length 属性可以确定 Storage 对象中保存了多少名/值对。


sessionStorage 对象

sessionStorage 对象只存储会话数据,这意味着数据只会存储到浏览器关闭

这跟浏览器关闭时会消失的会话 cookie 类似。

存储在 sessionStorage 中的数据不受页面刷新影响,可以在浏览器崩溃并重启后恢复。sessionStorage 对象与服务器会话紧密相关,所以在运行本地文件时不能使用

因为 sessionStorage 对象是 Storage 的实例,所以可以通过使用 setItem()方法或直接给属性赋值给它添加数据。

// 使用方法存储数据
sessionStorage.setItem("name", "wl");
// 使用属性存储数据
sessionStorage.name = "wl"; 
复制代码

所有现代浏览器在实现存储写入时都使用了同步阻塞方式,因此数据会被立即提交到存储。也就是说

通过 Web Storage 写入的任何数据都可以立即被读取

对存在于 sessionStorage 上的数据,可以使用 getItem()或直接访问属性名来取得。

// 使用方法取得数据
let name = sessionStorage.getItem("name");
// 使用属性取得数据
let name2 = sessionStorage.name;
复制代码

也可以结合 sessionStoragelength 属性和 key()方法遍历所有的值

+ let len = sessionStorage.length;
for (let i = 0; i < len; i++){
+  let key = sessionStorage.key(i);
   let value = sessionStorage.getItem(key);
   console.log(`${key}=`${value}`);
}
复制代码

也可以使用 for-in 循环迭代 sessionStorage 的值:

for (let key in sessionStorage){
   let value = sessionStorage.getItem(key);
   console.log(`${key}=${value}`);
}
复制代码

localStorage 对象

localStorage 作为在客户端持久存储数据的机制

要访问同一个localStorage 对象,页面必须来自

  • 同一个域(子域不可以)
  • 在相同的端口
  • 使用相同的协议

同源页面,可以访问同一个localStorage

localStorageStorage 的实例,所以可以像使用 sessionStorage 一样使用 localStorage

// 使用方法存储数据
localStorage.setItem("name", "wl");
// 使用属性存储数据
localStorage.book = "bc";
// 使用方法取得数据
let name = localStorage.getItem("name");
// 使用属性取得数据
let book = localStorage.book;
复制代码

两种存储方法的区别在于存储在 localStorage 中的数据会保留到通过 JS 删除或者用户清除浏览器缓存

localStorage 数据不受页面刷新影响,也不会因关闭窗口、标签页或重新启动浏览器而丢失


存储事件

每当 Storage 对象发生变化时,都会在文档上触发 storage 事件

使用属性或 setItem()设置值、使用 deleteremoveItem()删除值,以及每次调用 clear()时都会触发这个事件。

这个事件的事件对象有如下 4 个属性。

  • domain:存储变化对应的域
  • key:被设置或删除的键
  • newValue:键被设置的新值,若键被删除则为 null。
  • oldValue:键变化之前的值

代码监听 storage 事件:

window.addEventListener("storage",
   (event) => alert('发生变化的域:${event.domain}'));
复制代码

限制

一般来说,客户端数据的大小限制是按照每个源(协议、域和端口)来设置的,因此每个源有固定大小的数据存储空间

大部分浏览器将localStoragesessionStorage 限制为每个源 5MB


IndexedDB

Indexed Database API 简称 IndexedDB,是浏览器中存储结构化数据的一个方案

IndexedDB 的设计几乎完全是异步的。为此,大多数操作以请求的形式执行,这些请求会异步执行,产生成功的结果或错误。

数据库

IndexedDB 是类似于 MySQLWeb SQL Database数据库

与传统数据库最大的区别在于,IndexedDB 使用对象存储而不是表格保存数据。IndexedDB 数据库就是在一个公共命名空间下的一组对象存储

使用 IndexedDB 数据库的第一步是调用 indexedDB.open()方法,并给它传入一个要打开的数据库名称。

  • 如果给定名称的数据库已存在,则会发送一个打开它的请求
  • 如果不存在,则会发送创建并打开这个数据库的请求

这个方法会返回 IDBRequest 的实例,可以在这个实例上添加 onerroronsuccess 事件处理程序。

let db,
 request,
 version = 1;
request = indexedDB.open("admin", version);
request.onerror = (event) =>
   alert(`错误码: ${event.target.errorCode}`);
request.onsuccess = (event) => {
   db = event.target.result;
}; 
复制代码

对象存储

建立了数据库连接之后,下一步就是使用对象存储。创建对象存储时必须指定一个键

upgradeneeded 事件中设置对象存储信息。

request.onupgradeneeded = (event) => {
 const db = event.target.result;
 // 如果存在则删除当前 objectStore。
 if (db.objectStoreNames.contains("users")) {
     db.deleteObjectStore("users");
 }
 // 设置对象存储,并指定usename为主键
 db.createObjectStore("users", { keyPath: "username" });
}; 
复制代码

事务

创建了对象存储之后,剩下的所有操作都是通过事务完成的。

事务要通过调用数据库对象的 transaction()方法创建。任何时候,只要想要读取或修改数据,都要通过事务把所有修改操作组织起来

let transaction = db.transaction("users");
复制代码

保在事务期间只加载 users 对象存储的信息。(参数也可以是数组)。

有了事务的引用,就可以使用 objectStore()方法并传入对象存储的名称以访问特定的对象存储。

  • add()/put():添加和更新对象
  • get():获取对象
  • delete():删除对象
  • clear():删除所有对象

这 5 个方法都创建新的请求对象

const transaction = db.transaction("users"),
      store = transaction.objectStore("users"),
      request = store.get("007");
request.onerror = (event) => alert("没有该项数据");
request.onsuccess = (event) => alert(event.target.result.firstName);
复制代码

一个事务可以完成任意多个请求,所以事务对象本身也有事件处理程序

  • onerror
  • oncomplete

这两个事件可以用来获取事务级的状态信息

transaction.onerror = (event) => {
 // 整个事务被取消
};
transaction.oncomplete = (event) => {
 // 整个事务成功完成
}; 
复制代码

限制

  • IndexedDB 数据库是与页面源(协议、域和端口)绑定的,因此信息不能跨域共享
    意味着 www.wl.combc.wl.com 会对应不同的数据存储
  • 每个源都有可以存储的空间限制
  • 针对IndexDB的简化使用

在官网提供了很多基于IndexDB包装的库,隐藏了一些比较啰嗦的数据库实例化等操作。

然后谁用了,都说好


其他不常见的数据持久化方案

::: block-1

WebSQL

用于存储较大量数据的缓存机制。

  • 将数据以数据库二维表的形式存储在客户端
  • 允许SQL语句的查询
  • 让浏览器实现小型数据库存储功能
  • 不是H5规范

核心方法

  • openDatabase()
  • transaction()
  • executeSql()

已废弃并且被IndexDB所替代 :::

::: block-1

Application Cache

允许浏览器通过manifest配置文件在本地有选择的存储JS/CSS/图片等静态资源的文件级缓存机制

当页面不是首次打开,通过特定的manifest文件配置描述来选择本地Application Cache里的文件。

已废弃并且被ServerWorkers所替代 :::

在昨天的文章中,我们介绍了Service Worker,而服务工作线程的一个主要能力是可以通过编程方式实现真正的网络请求缓存机制,其中利用CacheStorage实现该功能。

后记

分享是一种态度

参考资料: JS高级程序设计第四版

全文完,既然看到这里了,如果觉得不错,随手点个赞和“在看”吧。



相关实践学习
借助OSS搭建在线教育视频课程分享网站
本教程介绍如何基于云服务器ECS和对象存储OSS,搭建一个在线教育视频课程分享网站。
相关文章
|
JSON JavaScript 前端开发
基于promise用于浏览器和node.js的http客户端的axios
基于promise用于浏览器和node.js的http客户端的axios
74 0
|
3月前
|
Web App开发
Chrome——谷歌浏览器chrome如何模拟其他客户端
Chrome——谷歌浏览器chrome如何模拟其他客户端
105 1
Chrome——谷歌浏览器chrome如何模拟其他客户端
|
4月前
|
存储 前端开发 安全
JavaScript进阶 - 浏览器存储:localStorage, sessionStorage, cookies
【7月更文挑战第2天】探索Web存储:localStorage持久化,sessionStorage会话限定,cookies则伴随HTTP请求。了解它们的特性和限制,如localStorage的5MB容量限制、跨域问题,sessionStorage的生命周期,及cookies的安全与带宽消耗。使用时需权衡安全、效率与应用场景。示例代码展示存储与检索方法。
293 2
|
6月前
|
存储 JSON 安全
[浏览器系列] : 客户端本地存储
[浏览器系列] : 客户端本地存储
71 2
[浏览器系列] : 客户端本地存储
|
6月前
|
存储 JavaScript 前端开发
在浏览器中存储数组和对象(js的问题)
在浏览器中存储数组和对象(js的问题)
68 0
|
6月前
|
人工智能 搜索推荐 Linux
一个集 AI + 工具 + 插件 + 社区为一体的Arc 浏览器风格AI客户端
一个集 AI + 工具 + 插件 + 社区为一体的Arc 浏览器风格AI客户端
276 0
|
存储 缓存 算法
如何获取浏览器定位信息存储到浏览器缓存中?
如何获取浏览器定位信息存储到浏览器缓存中
97 0
|
存储 JSON JavaScript
可能不是史上最全但肯定能学会的浏览器存储教程
可能不是史上最全但肯定能学会的浏览器存储教程
124 0
|
存储 缓存 JavaScript
Vue(Vue2+Vue3)——38.浏览器存储(webStorage)
Vue(Vue2+Vue3)——38.浏览器存储(webStorage)
|
存储 负载均衡 前端开发
关于浏览器存储与登录鉴权我所知道的。
关于浏览器存储与登录鉴权我所知道的。
215 0