编程技术是改变世界的力量。
本站
当前位置:网站首页 > HTML/CSS > 正文

Web 存储技术(web存储技术)

gowuye 2023-10-13 10:11 22 浏览 0 评论

一、背景介绍

第一个Web存储的技术叫做Cookie,它是网站的身份证。是网站为了辨别用户身份,进行session(服务端的session)跟踪而存储在用户本地终端上的数据,也就是说它是存在电脑硬盘上的,一个很小的txt类型的文件。Cookie每次都会跟随http请求发送到服务端,也就是说每一个http请求都会带上我们的cookie数据,因此它存在一个安全性的问题。

cookie本身也是有很大的局限性的,首先它很小,主流的浏览器最大支持 4096 字节,除了最大字节的限制,每个网站的cookie个数(也就是每一个first每一个域)也是有限制的,一般浏览器是20个。除此之外,cookie还会默认跟随所有http请求发送,即使不需要使用这个cookie来鉴别用户但是它也是会跟随http请求发送的,这样就会造成一个网络资源的浪费。然后部分的浏览器还限制了总的cookie个数300个。

在cookie的诸多局限性下,Web Storage应运而生。Web Storage 解决了很多问题:

比如它支持存储大量数据,支持复杂的本地数据库,而且也不会默认跟随http请求。Web Storage主要是有四个:

  • SessionStorage
  • LocalStorage
  • WebSQL
  • indexedDB

二、Cookie的简单介绍

Cookie是HTML4的一个标准,它一般不需要考虑兼容。它是网站的一个身份证,服务器可以针对不同用户,做出不同的响应。cookie存储在用户的机器上是一个纯文本,就是一个txt文件并不是一个脚本,它不能执行东西只负责记录。浏览器每次请求都会带上当前网站的cookie。

Cookie分为两种类型,一种呢是会话cookie,也就是临时性的cookie,退出浏览器或者是关闭即删除;

另一种叫持久cookie,它会一直存在,存在的时间由特定的过期时间或者是有效期来决定。

Cookie的域 Domain决定了当前的一个cookie的权限,哪一个域可以使用这个cookie。

Cookie的路径 Path,下面一个简单的例子:

www.baidu.com id="123456" domain="www.baidu.com"
www.baidu.com/user id="123456" user="eric" domain="www.baidu.com" path="/user/"
?
www.baidu.com/search id="123456";
www.baidu.com/user/search id="123456" user="eric";

如上www.baidu.com设置了一个id等于123456,domain是www.baidu.com,然后另外一个跟第一个一样多设置了一个user,id相同,但是多了一个user=“Eric”,它的domain设置成了www.baidu.com,path就到了user下面。这两者设置完成之后,当我们访问www.baidu.com/search时百度只能拿到id,因为user="Eric"是属于user这个域下面的,也就是说在search下面是获取不到的,但是在www.baidu.com/user/search这个时候我们就可以获取到名叫Eric的user。Path也是一种权限的控制只是相较于域domain是低一级的。

Cookie的安全secure,如果这个属性为TRUE,那么网站只有在https的请求下面才会携带当前的cookie。

Cookie的HttpOnly这个属性如果为TRUE,那么就不允许JavaScript操作cookie。

因为cookie是存储在客户端一个独立的文件,因此服务器是无法分辨用户和攻击者的。关于cookie的目的分为两种:一种是跨站点脚本攻击,一种是跨站请求伪造。

三、SessionStorage

key-value的键值对,是HTML5新增的一个会话存储对象。

SessionStorage是临时保存在同一窗口,也就是同一标签页的数据。如果当前标签页关闭了,那么SessionStorage也就失效了。这也是SessionStorage最显著的一个特点:单页标签限制。

除此之外,它还有的一些特点有:

  • 同源策略,也就是在同一协议,同一主机名和同一端口下的同一tab
  • 只在本地存储,不会跟随http请求发送到服务器
  • 存储方式采用key-value键值对,这里面的value只能存字符串类型,如果存其他的会自动转换成字符串。
  • 存储上线限制达到了5MB,如果当前存储超出上限新的内容会把旧的内容覆盖但不会报错。

属性:

  • sessionStorage.length - 键值对数量
  • sessionStorage.key(int index) -> null
  • sessionStorage.getItem(string key) -> null
  • sessionStorage[string key]
  • sessionStorage.setItem(string key, string value)
  • sessionStorage.removeItem(string key)
  • sessionStorage.clear()

Json对象

  • JSON.stringify()
  • JSON.parse()

四、LocalStorage

LocalStorage也是在浏览器的Application下面有一个Local Storage,它和SessionStorage是十分相似的,同样是key-value键值对,也是HTML5的新增存储对象,它与SessionStorage的特点不同之处在于没有标签页的限制和在浏览器的无痕模式下LocalStorage是不允许读取的,永久性的存储,然后SessionStorage超出限制是覆盖不会报错而LocalStorage超出会报错。

特点**:

  • 同源策略,也就是在同一协议,同一主机名和同一端口下的同一tab
  • 没有标签页的限制
  • 只在本地存储,不会跟随http请求发送到服务器
  • 存储方式采用key-value键值对,这里面的value只能存字符串类型,如果存其他的会自动转换成字符串。
  • 存储上线限制达到了5MB,如果当前存储超出上限会报错。
  • 无痕模式下不可读取
  • 永久性存储

属性:

  • sessionStorage.length - 键值对数量
  • sessionStorage.key(int index) -> null
  • sessionStorage.getItem(string key) -> null
  • sessionStorage[string key]
  • sessionStorage.setItem(string key, string value)
  • sessionStorage.removeItem(string key)
  • sessionStorage.clear()

注意事项:LocalStorage和SessionStorage在web view是不可靠的,web view指的是在开发混合APP的时候使用了浏览器来实现我们的APP,这个时候是不可靠的,因为在浏览器崩溃的情况下数据可能没有存进去。

另外一个在IOS浏览器中不可重复setItem,如果重复会报错,然后这个时候我们需要先removeItem再添加item。

监听storage的变化

监听storage包括SessionStorage和LocalStorage。然后这里需要提到两个概念:同源和监听同源网页。

  • 同源:协议、域名、端口三者相同,同源的情况下我们可以共享SessionStorage和LocalStorage。
  • 同源策略还禁止不同源执行任何脚本。
http://localhost:63342/simpleApp/app/index.html#/
(协议) (域名) (端口) (路径)
  • 监听同源网页,但是同一网页是无效的
window.addEventListener("storage", function (event) {
 console.log(event.key);
 console.log(event.oldValue);
 console.log(event.newValue);
 console.log(event.url);
 console.log(event.storageArea);
});

五、IndexedDB

IndexedDB 背景

  • Storage(Storage指的是SessionStorage和LocalStorage)不适合存储大量的数据
  • Storage不能提供搜索功能
  • Storage不能建立索引,存储的内容也比较少
  • IndexedDB扩大了web存储的容量,可以达到250MB以上

基本概念

首先它是一个NoSQL,也就是一个非关系型数据库。MySQL和Oracle都是关系型数据库。意思就是说如果建立了两个表在关系型数据库里面我们可以通过一个外链把多个表联系起来,但是NoSQL不行,在NoSQL里面如果想要多个表关联起来,我们只能手动的在关联的表里面添加上需要关联的另外一个或多个表的id。这是NoSQL与MySQL两者之间的一个区别。

IndexedDB的特点也是和Storage是一样的:

  • 键值对储存 ,但是允许所有类型,不允许主键重复报错
  • 是一个异步操作, 不阻塞浏览器线程
  • 支持事务,事务是SQL数据库的一个概念,也就是说我们进行任何的增删改查都要在某一个事务下面进行,提供了一个回滚功能,一系列操作有一步失败, 数据库回滚到事务发生之前的状态,这样为了避免操作中途出现失败,影响整个数据库的状态
  • 同源限制
  • 支持二进制储存

IndexedDB几个基本概念:

  • IDBDatabase - 数据库
  • IDBObjectStore - 对象仓库
  • IDBIndex - 索引
  • IDBTransaction - 事务
  • IDBRequest - 操作请求
  • IDBCursor - 指针
  • IDBKeyRange - 主键集合

IndexedDB浏览器兼容

IDBDatabase

IDB是IndexedDB的缩写,它呢就是数据库,数据库也叫作数据的一个容器。每一个源(同源策略)可以建立很多数据库。Database有一个版本的概念,版本对应着数据库表,同一时刻只能存在一个版本。比如:新增一个表,然后我们需要把database的版本加一,表里面要新增一列,这时同样需要把数据库版本加一。

注意:1 同一时刻只能有一个版本存在

? 2 修改数据库结构只能通过升级数据库版本

  • 打开数据库
/* databaseName不存在则创建 */
/* version为整数, 新建时为1 */
?
let database;
let userStore;
const request = window.indexedDB.open(databaseName, version);
?
/* 成功打开数据库 */
request.onsuccess = event => {
 database = request.result;
}
?
/* 打开数据库失败 */
request.onerror = error => {
 console.log(error);
}
?
/* 版本号大于当前数据库版本 */
request.onupgradeneeded = event => {
 database = event.target.result;
}

注意:如果在打开数据库时,数据库不存在,将会新建一个

IDBObjectStore(数据库表)

创建表,最好是在upgradeneeded下执行;在创建数据库表的时候需要指定主键,主键代表了唯一的标识,比如 keyPath:‘id’;如果不指定主键,我们可以指定一个autoIncrement:true,自增的一个概念,也就是不指定主键数据库会自动添加主键而且这个主键就是数字,依次递增的。

const createStore = () => {
 //如果当前的objectStoreNames.contains包含user,如果不包含user这个表,然后就用这个database.createObjectStore创建了一个表,这个表的名字就叫做user,然后主键就是下面的id
 if(!db.objectStoreNames.contains('user')) {
 userStore = database.createObjectStore('user', { keyPath: 'id' });
 }
}

指定索引:

const createStore = () => {
 if(!database.objectStoreNames.contains('user')) {
 userStore = database.createObjectStore('user', { keyPath: 'id' });
 userStore.createIndex('name', 'name', { unique: true });
 }
}

IDBTransaction(事务)

创建完之后需要往里面添加数据,添加数据我们就需要使用到事务。

事务涉及到数据库的增删改查,它有三个状态:

  • complete
  • error
  • abort

属性:

  • IDBTransaction.db 当前数据库
  • IDBTransaction.mode 模式,使用模式分为readonly和readwrite
  • IDBTransaction.objectStoreNames 当前数据库涉及到的哪几个数组表
  • IDBTransaction.error 回调

数据库的基本操作:增删改查以及清空。

新增数据(add)

分为两种情况:一种是使用自增的数据库的id或者是自增的一个键值,如果已经创建主键,那么新增必须包含主键和另一种已创建主键但主键不可重复。

const add = () => {
 /* 创建事务 */
 /* 使用某个数据库 */
 /* add新增 */
 transactionRequest = database.transaction(['user'], 'readwrite')
 .objectStore('user')
 .add({ id: 100, name: 'Eric', age: 28, email: 'Ericlee00@163.com' });
?
 /* 成功 */
 transactionRequest.onsuccess = event => {
 console.log('数据写入成功', event);
 };
?
 /* 失败 */
 transactionRequest.onerror = error => {
 console.log('数据写入失败', error);
 }
}

读取数据(get)

const read = () => {
 /* 创建事务 */
 transaction = database.transaction(['user']);
 /* 选择数据库表 */
 table = transaction.objectStore('user');
 /* 读取数据 */
 transactionRequest = table.get(2);
?
 /* 成功 */
 transactionRequest.onerror = event => {
 console.log('数据读取失败', event);
 };
?
 /* 失败 */
 transactionRequest.onsuccess = event => {
 if (transactionRequest.result) {
 console.log('数据读取成功', transactionRequest.result);
 } else {
 console.log('未读取到数据');
 }
 };
}

更新数据(put)

更新不存在的数据时会新建,也就是说在新增数据时如果相同,往往会出错,但是在更新数据时不会出错。如果数据不存在就会新建,如果存在就会一直更新。

const update = () => {
 transactionRequest = database.transaction(['user'], 'readwrite')
 .objectStore('user')
 .put({ id: count, name: 'David', age: 35, email: 'David@xiakedao.com' });
?
 transactionRequest.onsuccess = function (event) {
 console.log('更新数据成功', event);
 };
?
 transactionRequest.onerror = error => {
 console.log('更新数据失败', error);
 }
 }

删除数据(delete)

const delete = () => {
 transactionRequest = database.transaction(['user'], 'readwrite')
 .objectStore('user')
 .delete(2);
?
 transactionRequest.onsuccess = function (event) {
 console.log('删除数据成功', event);
 };
?
 transactionRequest.onerror = error => {
 console.log('删除数据失败', error);
 }
 }

清空数据(clear)

IDBCursor(指针)

提供了一种遍历数据的可能。

const readAll = () => {
 table = database.transaction('user').objectStore('user');
?
 table.openCursor().onsuccess = () => {
 let cursor = event.target.result;
?
 if (cursor) {
 console.log('数据遍历', cursor);
 cursor.continue();
 } else {
 console.log('数据遍历完成');
 }
 };
 }

关闭IndexedDB数据库连接

const closeDataBase = () => {
 database.close();
}

删除IndexedDB数据库前,须先关闭数据库连接

const deleteDataBase = () => {
 indexedDB.deleteDatabase('first_database');
}

六、WebSQL

基本概念:并不是 HTML5 的规范 , 只能算是一个独立的规范;使用WebSQL是完完全全的SQL 语句,使用SQL语句来操作客户端数据库;它一共有三个比较重要的概念,分别是:openDatabase 打开数据库,可以是使用现有数据库或者新建数据库;transaction 事务,所有的数据库都支持事务;executeSql 执行SQL语句。

openDatabase(打开数据库)

相比于IndexedDB的概念稍微多一点,主要是有数据库名称、版本号(在IndexedDB里面版本号都是整数,但是在WebSQL里面它可以是小数)、描述文本(介绍数据库是干什么的)、数据库大小和创建回调(function,只在第一次创建的时候才会调用)。

const database = openDatabase('my_database', '1.0', 'first', 2 * 1024 * 1024, function() {
?
});

Transaction(事务)

  • 创建表
const createTable = () => {
 database.transaction(function (content) { 
 content.executeSql('CREATE TABLE IF NOT EXISTS USER (id unique, name)');
 });
}
  • 添加数据
const addData = () => {
 database.transaction(function (content) { 
 content.executeSql('INSERT INTO USER (id, name) VALUES (1, "Eric")');
 });
}
  • 查询数据
const searchData = () => {
 database.transaction(function (content) { 
 content.executeSql('SELECT * FROM USER');
 });
}
  • 更新数据
const updateData = () => {
 database.transaction(function (content) { 
 content.executeSql('UPDATE USER SET name=\'David\' WHERE id=1');
 });
}
  • 删除数据库表
const deleteDataBase = () => {
 database.transaction(function (content) { 
 content.executeSql('DROP TABLE USER');
 });
 }

相关推荐

python中调试pdb_python怎么调试
python中调试pdb_python怎么调试

当你的Python程序出现错误或行为不符合预期时,调试工具是一种非常有用的方式来帮助你找到问题所在。Python内置了一个强大的调试器模块,称为pdb(Pyth...

2023-10-22 12:21 gowuye

vue3+tsx开发语法详解_vue3+typescript
vue3+tsx开发语法详解_vue3+typescript

很多组件库都使用了TSX的方式开发,主要因为其灵活性比较高,TSX和SFC开发的优缺点就不介绍了,这里主要说一下将SFC项目改造为TSX的过程。安装JSX库pn...

2023-10-22 12:20 gowuye

对前端初学者的一些帮助(常见名词解释)
对前端初学者的一些帮助(常见名词解释)

1.HTML:HTML是超文本标记语言,“超文本”就是指页面内可以包含图片、链接,甚至音乐、程序等非文字元素。2.CSS:主要用来设计网页的样式,美化网页;...

2023-10-22 12:20 gowuye

JAVA多线程详解(超详细)_java多线程菜鸟教程
JAVA多线程详解(超详细)_java多线程菜鸟教程

一、线程简介1、进程、线程程序:开发写的代码称之为程序。程序就是一堆代码,一组数据和指令集,是一个静态的概念。进程(Process):将程序运行起来,我们称之...

2023-10-22 12:19 gowuye

一文搞懂什么时候用 Runnable?什么时候用 Callable ?

今天我们看一道leetcodehard难度题目:统计可以被K整除的下标对数目。题目给你一个下标从0开始、长度为n的整数数组nums和一个整数k,返回满足下述条件的下标对(i...

优化重复冗余代码的8种方式_优化重复冗余代码的8种方式是什么

日常开发中,我们经常会遇到一些重复代码。大家都知道重复代码不好,它主要有这些缺点:可维护性差、可读性差、增加错误风险等等。最近呢,我优化了一些系统中的重复代码,用了好几种的方式。感觉挺有用的,所以本文...

高级 CSS 和 Sass:Flexbox、网格、动画等等!
高级 CSS 和 Sass:Flexbox、网格、动画等等!

Udemy-高级CSS和Sass:Flexbox、网格、动画等等!讲师:JonasSchmedtmann下载:口袋资源网高级CSS和Sass:...

2023-10-22 12:19 gowuye

我们现在正处于 JavaScript 消亡的边缘?
我们现在正处于 JavaScript 消亡的边缘?

每10年JavaScript都会发生一次改朝换代式的变革。在我看来,JavaScript当前正处于一次快速变革的开始,而这段时期未来可能会被称为Ja...

2023-10-22 12:19 gowuye

CSS预编译器三剑客及PostCSS_前端预编译css有哪几种
CSS预编译器三剑客及PostCSS_前端预编译css有哪几种

这篇文章包含两个部分,第一部分是个CSS预编译器:Sass、Less、Stylus,他们之间的对比,第二部分是现在大火的PostCSS。为什么会出现CSS预编译...

2023-10-22 12:18 gowuye

CSS预处理语言Sass入门_css3预处理器
CSS预处理语言Sass入门_css3预处理器

1.引言CSS3之前的CSS都大都是枚举属性样式,而编程语言强大的变量、函数、循环、分支等功能基本都不能在CSS中使用,让CSS的编程黯淡无光,Sass就是一...

2023-10-22 12:18 gowuye

“金三银四”,让我们愉快的开始准备Web面经吧:CSS篇
“金三银四”,让我们愉快的开始准备Web面经吧:CSS篇

前言又到了一年一度的“金三银四的季节了”。不过恐怕大家都有感觉,当下,正面临着近几年来的最严重的互联网寒冬,因此今天的“金三银四”肯定又是一场更为惨烈的江湖厮杀...

2023-10-22 12:18 gowuye

sass @extend(继承)指令详解_sass内置函数总结

在设计网页的时候常常遇到这种情况:一个元素使用的样式与另一个元素完全相同,但又添加了额外的样式。通常会在HTML中给元素定义两个class,一个通用样式,一个特殊样式。普通CSS的实现接下来以警...

Sass混合的使用_sas中如何合并两组数据

本节我们学习Sass中的混合,Sass中的混合是通过@mixin指令来定义的,混合允许我们定义可以在整个样式表中重复使用的样式,避免使用无语意的类。混合可以包含所有的CSS规则和任何其他...

css代码规范工具stylelint_代码规范

css样式的书写顺序及原理——很重要!很重要!很重要!为什么重要???概括讲就是,它涉及了浏览器的渲染原理:reflow和repaint还想知道更多为什么可以参考:https://blog.csdn....

CSS-in-JS 是恶魔还是天使?_天启四骑士是恶魔还是天使
CSS-in-JS 是恶魔还是天使?_天启四骑士是恶魔还是天使

有些人极为讨厌CSS-in-JS,单单提起这个名字都会让他们反感,总之就是拒绝二字。他们认为样式不属于JavaScript,而是属于CSS,并且CSS...

2023-10-22 12:17 gowuye

取消回复欢迎 发表评论: