cookie
- 存活期:cookie可设置为长时间放弃
- 作用范畴:cookie存储在客户端,发送http申请时会将cookie增加到cookie头字段,发送给服务器
- 存储量:单个cookie保留的数据不能超过4K。
session
session是另一种记录服务器和客户端会话状态的机制。session是基于cookie实现的,session存储在服务器端,sessionId会被存储到客户端的cookie中。
- 存活期:session 个别生效工夫较短,客户端敞开或者session 超时都会生效。
- 作用范畴:session存储在服务端,安全性绝对cookie要好一些。
- 存储量:session存储没有下限,但出于对服务器的性能思考,session内不要寄存过多的数据,并且须要设置session删除机制。
token
- 简略token的组成: uid(用户惟一的身份标识)、time(以后工夫的工夫戳)、sign(签名,token 的前几位以哈希算法压缩成的肯定长度的十六进制字符串)
- token:服务端验证客户端发送过去的token时,还须要查询数据库获取用户信息,而后验证token是否无效。 每一次申请都须要携带token,须要把token放到http的Header里。基于token的用户认证是一种服务端无状态的认证形式,服务端不必寄存token数据。用解析token的计算工夫换取session的存储空间,从而加重服务器的压力,缩小频繁的查询数据库。
jwt
- JSON Web Token(简称 JWT)是目前最风行的跨域认证解决方案。是一种认证受权机制。JWT是为了在网络应用环境间传递申明而执行的一种基于JSON的凋谢规范(RFC 7519)。JWT的申明个别被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源。比方用在用户登录上
- 将token和payload加密后存储于客户端,服务端只须要应用密钥解密进行校验(校验也是jwt本人实现的)即可,不须要查问或者缩小查询数据库,因为jwt自蕴含了用户信息和加密的数据。
sessionStorage
- 存活期:sessionStorage是会话级别贮存,在浏览器或页面敞开时数据就会销毁。不同的浏览器tab页面不雷同
- 作用范畴:只是客户端的贮存,不会波及到服务器贮存
- 存储量:localStorage和sessionStorage个别有5M
localStorage
- 存活期:localStorage是长久化的本地贮存,不刻意去删除数据, 数据是不会销毁的。不同的浏览器tab页面雷同。
- 作用范畴:只是客户端的贮存,不会波及到服务器贮存。
- 存储量:localStorage和sessionStorage个别有5M。
- 数据结构:键值键,值只能是字符串
storage事件:
- 当同源页面的某个页面批改了localStorage,其余的同源页面只有注册了storage事件,就会触发
示例
// 页面A监听import React, { useEffect } from 'react';const HomePage = () => {const handleStorage = (e) => { console.log('e', e);};useEffect(() => { window.addEventListener('storage', handleStorage); return () => { window.removeEventListener('storage', handleStorage); };}, []);return <div style={{ height: 'calc(100vh - 60px)', overflow: 'scroll' }}></div>;};export default HomePage;// 页面B触发localStorageimport React from 'react';const SubPage = () => {return ( <div style={{ height: 'calc(100vh - 60px)', overflow: 'scroll' }}> <button onClick={() => { localStorage.setItem('zlz_test_storage', 'test-' + Math.ceil(Math.random() * 20)); }} > localStorage </button> </div>);};export default SubPage;
- 同页面触发,需额定自定义事件实现
Event
和dispatchEvent
const originSetItem = localStorage.setItem; localStorage.setItem = function (key, value) { const setItemChange = new Event('storage'); setItemChange.key = key; setItemChange.oldValue = localStorage.getItem(key); setItemChange.newValue = value; window.dispatchEvent(setItemChange); originSetItem.apply(this, arguments); };
indexDB
- IndexedDB次要用于客户端存储大量结构化数据(包含, 文件/ blobs)。该API应用索引来实现对该数据的高性能搜寻。尽管 Web Storage 对于存储较大量的数据很有用,但对于存储更大量的结构化数据来说,这种办法不太有用
- IndexedDB是一个基于JavaScript的面向对象的数据库。 它容许咱们存储和检索用键索引的对象;能够存储结构化克隆算法反对的任何对象。 咱们只须要指定数据库模式,关上与数据库的连贯,而后检索和更新一系列事务。
- 浏览器的本地数据库,异步,也有同源限度,容量在250M以上甚至没有限度
- 繁难封装
// DBUtils.tsinterface EventResponse extends EventTarget { target: { result: IDBDatabase | unknown; };}type DBMethods = { getItem: (key: string) => Promise<unknown>; getAllItem: () => Promise<unknown>; getAllKeys: () => Promise<unknown>; setItem: (key: string, value: string | number | boolean | unknown[] | Record<string, unknown>) => Promise<unknown>; removeItem: (key: string) => Promise<unknown>; removeAll: () => Promise<unknown>;};interface DBUtilOption { dbName?: string; version?: number; keyPath?: string;}export default class DBUtils { dbName: string; DBOpenResult: Promise<unknown>; db: IDBDatabase | undefined; keyPath: string; constructor(config: DBUtilOption = {}) { const { dbName = 'cache', version = 1, keyPath = 'id' } = config; this.dbName = dbName; this.keyPath = keyPath; this.DBOpenResult = new Promise((resolve, reject) => { // 关上数据库 const request: IDBOpenDBRequest = window.indexedDB.open(this.dbName, version); request.onerror = () => { reject('数据库关上异样'); }; request.onsuccess = () => { this.db = request.result; resolve(''); }; request.onupgradeneeded = (event) => { const ev = (event as unknown) as EventResponse; const db = ev.target.result as IDBDatabase; db.onerror = function () { reject('数据库关上失败'); }; // 创立一个数据库存储对象 const objectStore: IDBObjectStore = db.createObjectStore(this.dbName, { keyPath, autoIncrement: !config.keyPath, }); // 建设一个索引, 没有配置则默认应用id objectStore.createIndex(keyPath, keyPath, { unique: true, }); }; }); } setItem: DBMethods['setItem'] = (key, value) => new Promise((resolve, reject) => { this.DBOpenResult.then(() => { if (!this.db) return; const transaction = this.db.transaction([this.dbName], 'readwrite'); // 关上曾经存储的数据对象 const objectStore = transaction.objectStore(this.dbName); // 增加到数据对象中 // { key: value} let values = {}; if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean' || Array.isArray(value)) { values[this.keyPath] = key; values[key] = value; } else { values = value; if (!value[this.keyPath]) { values[this.keyPath] = key; } } const objectStoreRequest = objectStore.put(values); objectStoreRequest.onsuccess = () => { resolve(''); }; objectStoreRequest.onerror = (err) => { console.error(`从数据库设置${key}异样`, err); reject(); }; }); }); getItem: DBMethods['getItem'] = (key) => new Promise((resolve, reject) => { this.DBOpenResult.then(() => { if (!this.db) return; const transaction = this.db.transaction([this.dbName], 'readonly'); const objectStore = transaction.objectStore(this.dbName); const objectStoreRequest = objectStore.index(this.keyPath).get(key); objectStoreRequest.onsuccess = () => { resolve(objectStoreRequest.result); }; objectStoreRequest.onerror = (err) => { console.error(`从数据库读取${key}异样`, err); reject(); }; }); }); getAllItem: DBMethods['getAllItem'] = () => { // let recordList = []; return new Promise((resolve, reject) => { this.DBOpenResult.then(() => { if (!this.db) return; const transaction = this.db.transaction([this.dbName], 'readonly'); const objectStore = transaction.objectStore(this.dbName); // const objectStoreRequest = objectStore.openCursor(); // objectStoreRequest.onsuccess = function (event) { // var cursor = event.target.result; // // 如果没有遍历完,持续上面的逻辑 // if (cursor) { // recordList.push(cursor.value); // // 持续下一个游标项 // cursor.continue(); // // 如果全副遍历结束 // } else { // resolve(recordList); // } // }; const objectStoreRequest = objectStore.getAll(); objectStoreRequest.onsuccess = function (event) { const ev = (event as unknown) as EventResponse; resolve(ev.target?.result); }; objectStoreRequest.onerror = (err) => { console.error(`从数据库读取异样`, err); reject(); }; }); }); }; getAllKeys: DBMethods['getAllKeys'] = () => new Promise((resolve, reject) => { this.DBOpenResult.then(() => { if (!this.db) return; const transaction = this.db.transaction([this.dbName], 'readonly'); const objectStore = transaction.objectStore(this.dbName); const objectStoreRequest = objectStore.getAllKeys(); objectStoreRequest.onsuccess = function (event) { const ev = (event as unknown) as EventResponse; resolve(ev.target?.result); }; objectStoreRequest.onerror = (err) => { console.error(`从数据库读取异样`, err); reject(); }; }); }); removeItem: DBMethods['removeItem'] = (key) => new Promise((resolve, reject) => { this.DBOpenResult.then(() => { if (!this.db) return; const transaction = this.db.transaction([this.dbName], 'readwrite'); const objectStore = transaction.objectStore(this.dbName); const objectStoreRequest = objectStore.delete(key); objectStoreRequest.onsuccess = () => { resolve(''); }; objectStoreRequest.onerror = (err) => { console.error(`从数据库删除${key}异样`, err); reject(); }; }); }); removeAll: DBMethods['removeAll'] = () => new Promise((resolve, reject) => { this.DBOpenResult.then(() => { if (!this.db) return; const transaction = this.db.transaction([this.dbName], 'readwrite'); const objectStore = transaction.objectStore(this.dbName); const objectStoreRequest = objectStore.clear(); objectStoreRequest.onsuccess = () => { resolve(''); }; objectStoreRequest.onerror = (err) => { console.error(`数据库清空异样`, err); reject(); }; }); });}
- 应用示例
import React from 'react';import DBUtils from './DBUtils';const HomePage = () => { const db = new DBUtils({ dbName: 'indexdb_test_001', keyPath: 'fileKey' }); const { removeAll, removeItem, getItem, setItem, getAllItem, getAllKeys } = db; const onSetValue = () => { const key = 'key-' + Math.ceil(Math.random() * 10); setItem(key, { data: 'xxxxxdddd' }); setItem('token', '222222'); }; const onGetValue = async () => { const res = await getItem('token'); console.log(res); }; const onGetAllValue = async () => { const res = await getAllItem(); const res2 = await getAllKeys(); console.log(res, res2); }; const onDeleteValue = async () => { await removeItem('1111'); }; const onClear = async () => { await removeAll(); }; return ( <div style={{ height: 'calc(100vh - 60px)', overflow: 'scroll' }}> <p> <button onClick={() => onSetValue()}>设置值</button> </p> <p> <button onClick={onGetValue}>获取值</button> </p> <p> <button onClick={onGetAllValue}>获取所有值</button> </p> <p> <button onClick={onDeleteValue}>删除值</button> </p> <p> <button onClick={onClear}>重置</button> </p> </div> );};export default HomePage;