二十五客户端存储

Posted 乘风xs

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二十五客户端存储相关的知识,希望对你有一定的参考价值。

1.Cookie

最初用于在客户端存储会话信息。这个规范要求服务器在响应HTTP请求时,发送set-cookie的HTTP头部,包含会话信息,浏览器在之后的每个请求中都会在Cookie头部字段中携带该信息。

// 响应头部,包含name
HTTP/1.1 200 OK
Content-type: text/html
Set-Cookie: name=value
Other-header: other-header-value 

//请求头部,携带name
GET /index.jsl HTTP/1.1
Cookie: name=value
Other-header: other-header-value 

1.1限制

cookie与特定的域绑定,保证cookie中的信息不会被其他域访问,只对于被认可的接受者开放。
浏览器中的限制

  • 不超过300个cookie
  • 每个cookie不超过4096字节
  • 每个域不超过20个cookie
    如果 cookie 总数超过了单个域的上限,浏览器就会删除之前设置的 cookie

1.2构成

参数说明
名称不区分大小写
字符串,必须经过URL编码
Cookie有效的域,发送到这个域的所有请求都会包含该cookie
路径请求的URL中包含该路径,才会把cookie发送至服务器
过期时间表示何时删除该cookie的时间戳,默认是会话结束时
安全标识设置之后,只有使用SSL安全链接,才会把cookie发送给服务器

这些参数在set-cookie头部中用分号加空格分隔开

HTTP/1.1 200 OK
Content-type: text/html
Set-Cookie: name=value; expires=Mon, 22-Jan-07 07:10:24 GMT; domain=.wrox.com
Other-header: other-header-value 
// 安全标识是唯一非键值对,只需要一个secure
HTTP/1.1 200 OK
Content-type: text/html
Set-Cookie: name=value; domain=.wrox.com; path=/; secure
Other-header: other-header-value 

1.3javascript中的cookie

接口只有document.cookie属性。
使用该属性获取值时,会返回该页面中所有有效的cookie字符串,且都是经过URL编码的,必须使用decodeURIComponent()解码。
设置值时,不会覆盖之前的任何cookie,除非设置的时之前存在的cookie,所有参数中,只有name和value是必须的,且使用之前,最好使用encodeURIComponent()编码。

document.cookie = encodeURIComponent("name") + "=" +
 encodeURIComponent("Nicholas") + "; domain=.wrox.com; path=/";
class CookieUtil 
 	static get(name) 
 		let cookieName = `$encodeURIComponent(name)=`,
 			cookieStart = document.cookie.indexOf(cookieName),
 			cookieValue = null;
 		if (cookieStart > -1)
 			let cookieEnd = document.cookie.indexOf(";", cookieStart);
 			if (cookieEnd == -1)
 				cookieEnd = document.cookie.length;
 			
			cookieValue = decodeURIComponent(document.cookie.substring(cookieStart + cookieName.length, cookieEnd));
 		
 		return cookieValue;
	
 	static set(name, value, expires, path, domain, secure) 
 		let cookieText = `$encodeURIComponent(name)=$encodeURIComponent(value)`
 		if (expires instanceof Date) 
 			cookieText += `; expires=$expires.toGMTString()`;
 		
 		if (path) 
 			cookieText += `; path=$path`;
 		
		if (domain) 
 			cookieText += `; domain=$domain`;
 		
 		if (secure) 
 			cookieText += "; secure";
 		
 		document.cookie = cookieText;
 	
 	static unset(name, path, domain, secure) 
 		CookieUtil.set(name, "", new Date(0), path, domain, secure);
 	
;

1.4子Cookie

为了绕过浏览器对每个域cookie的限制数量,有些开发者提出了子cookie的概念,本质是在一个cookie中,存储多个name/value对。

name=name1=value1&name2=value2&name3=value3&name4=value4&name5=value5 

1.5使用cookie的注意事项

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

2. Web Storage

  • 提供在Cookie之外的存储会话数据的途径
  • 提供跨会话持久化存储大量数据的途径

2.1 Storage类型

Storage只能存储字符串,在存储非字符串时会自动进行转换,这种转换在获取数据时不能撤销,即获取时永远都只能获取字符串数据。

方法说明
clear()删除所有值,firefox中未实现
getItem(name)获取name对应的value
key(index)取得给定index位置的名称
removeItem(name)删除给定name的名/值
setItem(name, value)设置给定的name/value

2.2 SessionStorage对象

sessionStorage 对象只存储会话数据,这意味着数据只会存储到浏览器关闭。这跟浏览器关闭时会消失的会话 cookie 类似。存储在 sessionStorage 中的数据不受页面刷新影响,可以在浏览器崩溃并重启后恢复。

// 新增数据的两种方法
sessionStorage.set('name', '红宝书');
sessionStorage.name = '红宝书';

// 获取数据的两种方法
sessionStorage.get('name');
sessionStorage.name;
// 也可以使用key()遍历
for (let i = 0, len = sessionStorage.length; i < len; i++)
	 let key = sessionStorage.key(i);
	 let value = sessionStorage.getItem(key);
	 console.log(`$key=`$value`);

几乎所有现代浏览器在实现存储写入时都使用了同步阻塞的方式,因此数据会被立即提交到存储。在老版IE浏览器中使用异步写入的方式.

//仅适用于IE8
sessionStorage.begin();
sessionStorage.name = '红宝书';
sessionStorage.learner = 'coderxsj';
sessionStorage.commit();

2.3 localStorage对象

在修订的 HTML5 规范里,localStorage 对象取代了 globalStorage,作为在客户端持久存储数据的机制。要访问同一个 localStorage 对象,页面必须来自同一个域(子域不可以)、在相同的端口上使用相同的协议。

// 使用方法存储数据
localStorage.setItem("name", "Nicholas");
// 使用属性存储数据
localStorage.book = "Professional JavaScript";
// 使用方法取得数据
let name = localStorage.getItem("name");
// 使用属性取得数据
let book = localStorage.book; 

2.4 存储事件

每当Storage对象发生变化的时候,都会在文档上触发storage事件s。使用属性或 setItem()设置值、使用 delete 或 removeItem()删除值,以及每次调用 clear()时都会触发这个事件。这个事件的事件对象有如下 4 个属性。

属性说明
domain存储变化发生的域
key被设置或者删除的键
newValue
oldValue
window.addEventListener('storage', (event) => 
	console.log(`Storage changed for $event.domain, the value of $event.key changes from $event.oldValue to $event.newValue`);
	);

2.5限制

  • 每个源限制大小为5M

3. IndexedDB

indexedDB是浏览器端的一个结构化数据存储的一个方案,其设计几乎完全是异步的,绝大多数IndexedDB操作需要添加onerror/onsuccess事件处理程序来确定输出。

3.1数据库

indexedDB是类似于mysql的数据库,其区别在于IndexedDB是使用对象而不是表格存储数据。
使用 IndexedDB 数据库的第一步是调用 indexedDB.open()方法,并给它传入一个要打开的数据库名称。如果给定名称的数据库已存在,则会发送一个打开它的请求;如果不存在,则会发送创建并打开这个数据库的请求。这个方法会返回 IDBRequest 的实例,可以在这个实例上添加 onerror 和onsuccess 事件处理程序。

let db,
 request,
 version = 1;
request = indexedDB.open("admin", version);
request.onerror = (event) => alert(`Failed to open: $event.target.errorCode`);
request.onsuccess = (event) => 
 db = event.target.result;
;

3.2 对象存储

数据库的版本决定了数据库模式,包括数据库中的对象存储和这些对象存储的结构。如果数据库还不存在,open()操作会创建一个新数据库,然后触发 upgradeneeded 事件。可以为这个事件设置处理程序,并在处理程序中创建数据库模式。如果数据库存在,而你指定了一个升级版的版本号,则会立即触发 upgradeneeded 事件,因而可以在事件处理程序中更新数据库模式

request.onupgradeneeded = (event) => 
	 const db = event.target.result;
	 // 如果存在则删除当前 objectStore。测试的时候可以这样做
	 // 但这样会在每次执行事件处理程序时删除已有数据
	 if (db.objectStoreNames.contains("users")) 
	 	db.deleteObjectStore("users");
	 
	 db.createObjectStore("users",  keyPath: "username" ); // 这里指定username属性作为存储的键
; 

3.3 事务

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

// 创建事务
let transaction = db.transaction();// 不指定参数,对所有的对象存储具有只读权限
let transaction1 = db.transaction('users'); // 对users对象存储的信息具有只读权限
let transaction2 = db.transaction(['users', 'students']);// 对多个对象存储的信息具有只读权限

要修改访问权限的话,需要传入第二个参数,其值为readonly, readwrite, versionchange

let transaction = db.transaction("users", "readwrite");

有了事务的引用,就可以使用objectStore()方法并传入对象存储的名称以访问特定的对象存储。然后,可以使用add()put()方法添加更新对象,使用 get()取得对象,使用delete()删除对象,使用 clear()删除所有对象。其中,get()和 delete()方法都接收对象键作为参数,这 5 个方法都创建新的请求对象。

const transaction = db.transaction("users"),
 	store = transaction.objectStore("users"),
 	request = store.get("007");
request.onerror = (event) => alert("Did not get the object!");
request.onsuccess = (event) => alert(event.target.result.firstName);

因为一个事务可以完成任意多个请求,所以事务对象本身也有事件处理程序:onerror oncomplete。这两个事件可以用来获取事务级的状态信息:

transaction.onerror = (event) => 
 // 整个事务被取消
;
transaction.oncomplete = (event) => 
 // 整个事务成功完成
;

3.4插入对象

拿到了对象存储的引用后,就可以使用 add()put()写入数据了。这两个方法都接收一个参数,即要存储的对象,并把对象保存到对象存储。这两个方法只在对象存储中已存在同名的键时有区别。这种情况下,add()会导致错误,而 put()会简单地重写该对象。更简单地说,可以把 add()想象成插入新值,而把 put()想象为更新值。

// users 是一个用户数据的数组
let request,
 	requests = [];
for (let user of users) 
	 request = store.add(user);
	 request.onerror = () => 
	 	// 处理错误
	 ;
	 request.onsuccess = () => 
	 	// 处理成功
	 ;
	 requests.push(request);

3.5通过游标查询

使用事务可以通过一个已知键取得一条记录。如果想取得多条数据,则需要在事务中创建一个游标游标是一个指向结果集的指针。与传统数据库查询不同,游标不会事先收集所有结果。相反,游标指向第一个结果,并在接到指令前不会主动查找下一条数据。
需要在对象存储上调用 openCursor()方法创建游标。与其他 IndexedDB操作一样,openCursor()方法也返回一个请求,因此必须为它添加 onsuccess 和 onerror 事件处理程序。

const transaction = db.transaction("users"),
 	store = transaction.objectStore("users"),
 	request = store.openCursor();
request.onsuccess = (event) => 
 	// 处理成功
;
request.onerror = (event) => 
 	// 处理错误
;

在调用 onsuccess 事件处理程序时,可以通过event.target.result 访问对象存储中的下一条记录,这个属性中保存着IDBCursor 的实例(有下一条记录时)或 null(没有记录时)。
IDBCursor对象的属性

属性说明
direction字符串常量,表示游标的方向及是否应该遍历所欲重复的值,NEXT(“next”),NEXTUNIQUE(“nextunique”),PREV(“prev”),PREVUNIQUE(“prevunique”)
key对象的键
value实际的对象
primaryKey游标使用的键

游标可用于更新个别记录。
update()方法使用指定的对象更新当前游标对应的值。
delelte()来删除游标位置的记录

// 更新当前值
request.onsuccess = (event) => 
	 const cursor = event.target.result;
	 let value,
	 	updateRequest;
	 if (cursor)  // 永远要检查
	 	if (cursor.key == "foo") 
	 		value = cursor.value; // 取得当前对象
	 		value.password = "magic!"; // 更新密码
	 		updateRequest = cursor.update(value); // 请求保存更新后的对象
	 		updateRequest.onsuccess = () => 
	 			// 处理成功
	 		;
	 		updateRequest.onerror = () => 
	 			// 处理错误
	 		;
	 	
	 
;
// 删除
request.onsuccess = (event) => 
	 const cursor = event.target.result;
	 let value,
	 	deleteRequest;
	 if (cursor)  // 永远要检查
		 if (cursor.key == "foo") 
			 deleteRequest = cursor.delete(); // 请求删除对象
			 deleteRequest.onsuccess = () => 
			 	// 处理成功
			 ;
			 deleteRequest.onerror = () => 
			 	// 处理错误
			 ;
		 
	 
;

默认情况下,每个游标只会创建一个请求。要创建另一个请求,必须调用下列中的一个方法。

  • continue(key):移动到结果集中的下一条记录。参数 key 是可选的。如果没有指定 key,游
    标就移动到下一条记录;如果指定了,则游标移动到指定的键。
  • advance(count):游标向前移动指定的 count 条记录。
request.onsuccess = (event) => 
	 const cursor = event.target.result;
	 if (cursor)  // 永远要检查
	 	console.log(`Key: $cursor.key, Value:$JSON.stringify(cursor.value)`);
	 	cursor.continue(); // 移动到下一条记录
	  else 
	 	console.log("Done!");
	 
; 

3.6键范围

使用游标会给人一种不太理想的感觉,因为获取数据的方式受到了限制。使用键范围(key range)可以让游标更容易管理。键范围对应IDBKeyRange的实例。
四种指定键范围的方法

// 1. only传入想要获取的键
const onlyRange = IDBKeyRange.only("007"); 

// 2.定义结果集的下限
// 从"007"记录开始,直到最后
const lowerRange = IDBKeyRange.lowerBound("007"); 
// 从"007"的下一条记录开始,直到最后
const lowerRange = IDBKeyRange.lowerBound("007", true); 

// 3.第三种键范围可以定义结果集的上限
// 从头开始,到"ace"记录为止
const upperRange = IDBKeyRange.upperBound("ace");
// 从头开始,到"ace"的前一条记录为止
const upperRange = IDBKeyRange.upperBound("ace", true);

// 4.同时指定上下限
// 从"007"记录开始,到"ace"记录停止
const boundRange = IDBKeyRange.bound("007", "ace");
// 从"007"的下一条记录开始,到"ace"记录停止
const boundRange = IDBKeyRange.bound("007", "ace", true);
// 从"007"的下一条记录开始,到"ace"的前一条记录停止
const boundRange = IDBKeyRange.bound("007", "ace", true, true);
// 从"007"记录开始,到"ace"的前一条记录停止
const boundRange = IDBKeyRange.bound("007", "ace", false, true); 

定义了范围之后,把它传给 openCursor()方法,就可以得到位于该范围内的游标:

const store = db.transaction("users").objectStore("users"),
	 range = IDBKeyRange.bound("007", "ace");
	 request = store.openCursor(range);
	request.onsuccess = function(event)
		 const cursor = event.target.result;
		 if (cursor)  // 永远要检查
		 	console.log(`Key: $cursor.key, Value: $JSON.stringify(cursor.value)`);
		 	cursor.continue(); // 移动到下一条记录
		  else 
		 	console.log("Done!");
	 
PHP SESSION

MySQL ------ 存储过程 (二十五)

MySQL ------ 存储过程简单使用(二十五 ---2)

408数据结构与算法—数组和特殊矩阵的压缩存储(二十五)

408数据结构与算法—数组和特殊矩阵的压缩存储(二十五)

JDK源码(二十五):Hashtable