二十五客户端存储
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