前端存储

HTTP cookies

HTTP Cookie(Web Cookie 或者浏览器 Cookie)
是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。通常,它用于告知服务端两个请求是否来自同一浏览器,如保持用户的登陆状态。Cookie 是基于无状态的HTTP协议记录稳定的状态信息成为了可能。

Cookie 的本职工作并非本地存储,而是“维持状态”
HTTP协议是无状态的,HTTP协议自身不对请求和响应之间的通信状态进行保存。
Cookie指某些网站为了辨别用户身份而储存在用户本地终端上的数据(通常经过加密)。 cookie是服务端生成,客户端进行维护和存储。

服务器 → 浏览器 → 存储在本地
浏览器再发起请求会携带 cookie → 服务器

Cookie 主要用于以下三个方面:

  • 会话状态管理(如用户登陆状态、购物车、游戏分数或其它需要记录的信息)
  • 个性化设置(如用户自定义设置、主题等)
  • 浏览器行为跟踪(如跟踪分析用户行为等)

Cookie 用于客户端数据的存储,随着浏览器开始支持各种各样的存储方法,Cookie 渐渐被淘汰。由于服务器指定 Cookie 后,浏览器的每次请求都会携带Cookie 数据,会带来额外的性能开销(尤其是在移动环境下)。新的浏览器API已经允许开发者直接将数据存储到本地,如使用 Web storage API(本地存储和会话村存储)或 IndexedDB。

  • Cookie 的大小受限,一般为 4 KB
  • 同一个域名下存放 Cookie 的个数是有限制的,不同浏览器的个数不一样,一般为 20 个
  • Cookie 支持设置过期时间,当过期时自动销毁
  • 每次发起同域下的 HTTP 请求时,都会携带当前域名下的 Cookie
  • 支持设置为 HttpOnly,防止 Cookie 被客户端的 JavaScript 访问

创建 Cookie
当服务器收到 HTTP 请求时,服务器可以在响应头里面添加一个 Set-Cookie选项。浏览器收到响应后通常会保存下 Cookie,之后对该服务器每次请求中都通过 Cookie 请求头部将 Cookie 信息发送给服务器。另外,Cookie 的过期时间、域、路径、有效期、适用站点都可以根据需要来指定。

Set-Cookie 响应头和 Cookie 请求头部
服务器使用 Set-Cookie 响应头部向用户代理(一般是浏览器)发送 Cookie信息。
Set-cookie : <cookie名> = <cookie值>
服务器通过该头部告知客户端保存 Cookie 信息。

PHP
Node.js
Python
Ruby on Rails

现在,对该服务器发起的每次新请求,浏览器都会将之前保存的 Cookie 信息通过 Cookie 请求头部发送给服务器。

会话期 Cookie :浏览器关闭之后它会被自动删除,它仅在会话期内有效。会话期 Cookie 不需要指定过期时间(Expires)或者有效期(Max-Age)。需要注意的是,有些浏览器提供了会话恢复功能,这种情况下即使关闭了浏览器,会话期 Cookie 也会被保留下来,就好像浏览器从来没有关闭一样。

和关闭浏览器的会话期 Cookie 不同,持久性 Cookie 可以指定一个特定的过期时间(Expires)或有效期(Max-Age)。

当 Cookie 的过期时间被设定时,设定的日期和时间只于客户端相关,而不是服务端。

标记为 Secure 的 Cookie 只应通过被 HTTPS 协议加密过的请求发送给服务端。但即便设置了 Secure 标记,敏感信息也不应该通过 Cookie 传输,因为 Cookie 有其固有的不安全性,Secure 标记也无法提供确定的安全保障。从 Chrome 52 和 Firefox 52 开始,不安全的站点 (http:)无法使用 Cookie 的 Secure 标记。

为避免跨域脚本(XSS)攻击,通过 Javascript 的 Document.cookie API 无法访问带有 HttpOnly 标记的 Cookie,它们只应该发送给服务器。如果包含服务端 Session 信息的 Cookie 不想被客户端 Javascript 脚本调用,那么就应该为其设置 HttpOnly 标记。

Domain 和 Path 标识定义了 Cookie的作用域:即 Cookie 应该发送那些 URL。

Domain 标识指定了哪些主机可以接收 Cookie。如果不指定,默认为当前文档的主机(不包含子域名)。如果指定了 Domain ,则一般包含子域名。

例如:
如果设置 Domain = mozilla.org,则 Cookie 也包含在子域名中 (如 developer.mozilla.org)。

Path 标识指定了主机下哪些路可以接收 Cookie (该 URL 路径必须存在于请求 URL 中)。以字符 %x2F (”/“)作为路径分隔符,子路径也会被匹配。

例如,设置 Path = /docs,则以下地址都会匹配:

/docs
/docs/Web
/docs/Web/HTTP

SameSite Cookies

SameSite Cookie 允许服务器要求某个 cookie 在跨站请求时不会被发送,从而可以阻止跨站请求伪造攻击(CSRF)。但是目前 SameSite Cookie 还处于实验阶段,并不是所有浏览器都支持。

通过 Document.cookie 属性可创建新的 Cookie ,也可通过该属性访问非 HttpOnly 标记的 Cookie。

1
2
3
4
document.cookie = "yummy_cookie=choco"; 
document.cookie = "tasty_cookie=strawberry";
console.log(document.cookie);
// logs "yummy_cookie=choco; tasty_cookie=strawberry"
1
2
3
4
5
6
// 得到名为 test2 的 cookie
document.cookie = "test1=Hello";
document.cookie = "test2=World";

var myCookie = document.cookie.replace(/(?:(?:^|.*;\s*)test2\s*\=\s*([^;]*).*$)|^.*$/, "$1");
alert(myCookie);

请留意在安全节提到的安全隐患,JavaScript 可以通过跨站脚本攻击 (XSS)的方式来窃取 Cookie。

安全

当机器处于不安全环境时,切记不能通过 HTTP Cookie 存储、传输敏感信息。

会话劫持和XSS

在 Web 应用中,Cookie 常用来标记用户或授权会话。Web 应用的Cookie 被窃取,可能导致授权用户的会话受到攻击。常用的窃听 Cookie 的方式有利用社会工程学攻击和利用应用程序漏洞进行 XSS 攻击。

HttpOnly 类型的 Cookie 由于阻止了 JavaScript 对其的访问性而能在一定程度上缓解此类攻击。

跨站请求伪造(CSRF)

阻止此类事件的发生:

  • 对用户输入进行过滤来阻止 XSS;
  • 任何敏感操作都需要确认;
  • 用于敏感信息的 Cookie 只能拥有较短的生命周期;

session

为什么要有 session?
HTTP是无状态的

web 应用的特点

  • 用户每执行一个操作,就要与服务器重新建立一个连接

http是无状态的

  • 每次操作建立的连接,在操作结束后,连接都会断开
  • 连接断开后,连接所使用的资源,默认都自动释放

优点:快速释放资源,给其它更多的人,增大服务器的负载能力
缺点:即使同一个用户的新连接,也无法得到上次连接的状态和数据

Session:是服务器内存中的一个对象

session 允许将数据库在Web服务器上,从而在整个用户会话过程中保持任何数据。

用户会话是指用户在浏览器某个网站时,从进入网站到关闭浏览器搜经过的这段时间

生命周期

打开新浏览器窗口,首次请求服务器时,浏览器就与服务器建立 session。服务器自动给客户端分配一个唯一的标识(sessionid)被存储于
cookie中。
强调:从当前浏览器窗口打开的新链接,不再建立新session,而是和第一打开的窗口共用同一个session。

Web Storage

Web Storage 包括如下两种机制:

  • sessionStorage 为每个给定的源 (give origin)维持一个独立的存储区域,该存储区域在页面会话期间可用(即只能浏览器处于打开状态,包括页面重新加载和恢复)。
  • localStorage 同样的功能,但是在浏览器关闭,然后重新打开后数据仍然存在。

这两种机制是通过 window.sessionStorage 和 window.localStorage 属性使用(更确切的说,在支持的浏览器中 Window 对象实现了 WindowLocalStorage和 WindowSessionStorage 对象并挂在其 localStorage 和 sessionStorage属性下)—— 调用其中任一对象会创建 Storage 对象,通过 Storage 对象,可以设置、获取和移动数据项,对于每个源(origin)sessionStorage 和 localStorage 使用不同的 Storage 对象 —— 独立运行和控制。

localStorage

存储在 localStorage 的数据可以长期保留;

localStorage 的特点

  • 大小限制为 5MB ~10MB;
  • 在同源的所有标签页和窗口之间共享数据;
  • 数据仅保存在客户端,不与服务器进行通信;
  • 数据持久存在且不会过期,重启浏览器后仍然存在;
  • 对数据的操作是同步的。

基础用法

1
2
3
4
5
6
7
8
//  添加修改
localStorage.setItem('myCat', 'Tom');
// 读取 localStorage
let cat = localStorage.getItem('myCat');
// 移除 localStorage 项
localStorage.removeItem('myCat');
// 移除所有的 localStorage
localStorage.clear();

localStorage 功能检测

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//  测试可用性
function storageAvailable(type) {
var storage;
try {
storage = window[type];
var x = '__storage_test__';
storage.setItem(x, x);
storage.removeItem(x);
return true;
}
catch(e) {
return e instanceof DOMException && (
// everything except Firefox
e.code === 22 ||
// Firefox
e.code === 1014 ||
// test name field too, because code might not be present
// everything except Firefox
e.name === 'QuotaExceededError' ||
// Firefox
e.name === 'NS_ERROR_DOM_QUOTA_REACHED') &&
// acknowledge QuotaExceededError only if there's something already stored
(storage && storage.length !== 0);
}
}
// 测试 localStorage
if (storageAvailable('localStorage')) {
// Yippee! We can use localStorage awesomeness
}
else {
// Too bad, no localStorage for us
}
// 测试 sessionStorage
storageAvailable('sessionStorage')

兼容性

cookies 对 localStorage 对象的实现。

localStorage

sessionStorage

sessionStorage 是一种会话级别的缓存,关闭浏览器时数据会被清除

sessionStorage 的特点

  • 页面会话在浏览器打开期间一直保持,并且重新加载或恢复页面仍会保持原来的页面会话。
  • 在新标签或窗口打开一个页面时会复制顶级浏览会话的上下文作为新会话的上下文,这点和 session cookies 的运行方式不同。
  • 打开多个相同的URL的Tabs页面,会创建各自的sessionStorage。
  • 关闭对应浏览器tab,会清除对应的sessionStorage
  • 与 localStorage 拥有统一的 API 接口;
  • 对数据的操作是同步的。

基础用法

1
2
3
4
5
6
7
8
9
//  添加修改数据
sessionStorage.setItem('key', 'value');
// 获取数据
let data = sessionStorage.getItem('key');
// 删除数据
sessionStorage.removeItem('key');
// 清除数据
sessionStorage.clear();

Web SQL

HTML5 已经放弃 Web SQL 数据库。

Web SQL Database 规范中定义的三个核心方法

  • openDatabase:这个方法使用现有数据库或新建数据库来创建数据库对象;
  • transaction:这个方法允许我们根据情况控制事务的提交或回滚;
  • executeSql:这个方法用于执行真实的 SQL 语句。

Web SQL 的特点

  • Web SQL 能方便进行对象存储;
  • Web SQL 支持事务,能方便地进行数据查询和数据处理操作。

基础用法

1
2
3
4
5
6
7
8
9
var db = openDatabase('mydb', '1.0', 'Test DB', 2 * 1024 * 1024);

db.transaction(function (tx) {
// 执行查询操作
tx.executeSql('CREATE TABLE IF NOT EXISTS LOGS (id unique, log)');
// 执行插入操作
tx.executeSql('INSERT INTO LOGS (id, log) VALUES (1, "foobar")');
tx.executeSql('INSERT INTO LOGS (id, log) VALUES (2, "logmsg")');
});

IndexedDB

IndexedDB 是一种低级API,用于客户端存储大量结构化数据(包括,文件/blobs)。该API 使用索引实现对该数据的高性能搜索。虽然 Web Storage 对于存储较少量的数据很有用,对于存储更大量的结构化数据 IndexedDB 提供了一个解决方案。

IndexedDB 是一个事务性数据库系统,类似于基于 SQL 的 RDBMS。不同的是它使用固定的列表,IndexedDB 是一个基于 JavaScript 的面向对象的数据库。IndexedDB 允许您存储和检索用检索用键索引的对象;可以存储 structured clone algorithm 支持的任何对象。只需要指定数据库模式,打开于数据库的连接,然后检索和更新一些列事务中的数据。

IndexedDB 是一种可以让你在用户的浏览器内持久化存储数据的方法。IndexedDB 为生成 Web Application 提供了丰富的查询能力,使我们的应用在在线和离线时都可以正常工作。

IndexedDB 的特点

  • 存储空间大:存储空间可以达到几百兆甚至更多;
  • 支持二进制存储:它不仅可以存储字符串,而且还可以存储二进制数据;
  • IndexedDB 有同源限制,每一个数据库只能在自身域名下能访问,不能跨域名访问;
  • 支持事务型:IndexedDB 执行的操作会按照事务来分组的,在一个事务中,要么所有的操作都成功,要么所有的操作都失败;
  • 键值对存储:IndexedDB 内部采用对象仓库(object store)存放数据。所有类型的数据都可以直接存入,包括 JavaScript 对象。对象仓
    库中,数据以 “键值对” 的形式保存,每一个数据记录都有对应的主键,主键是独一无二的,不能有重复,否则会抛出一个错误。
  • 数据操作是异步的:使用 IndexedDB 执行的操作是异步执行的,以免阻塞应用程序。

基础用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
var dbName = "my_db";
// 打开数据库
var request = indexedDB.open(dbName, 2); // 数据库名称 数据库版本
// 打开数据库失败
request.onerror = function(event) {
// 错误处理
};
// 如果指定的版本号,大于数据库的实际版本号,就会发生数据库升级事件upgradeneeded。
request.onupgradeneeded = function(event) {
// 拿到数据库实例
var db = event.target.result;

// 建立一个对象仓库来存储我们客户的相关信息,我们选择 ssn 作为键路径(key path)
// 因为 ssn 可以保证是不重复的 ssn 是主键
var objectStore;
if (!db.objectStoreNames.contains('person')) {
objectStore = db.createObjectStore("customers", { keyPath: "ssn" });
// IndexedDB 自动生成主键。
// var objectStore = db.createObjectStore( 'person', { autoIncrement: true })
}

// 建立一个索引来通过姓名来搜索客户。名字可能会重复,所以我们不能使用 unique 索引
objectStore.createIndex("name", "name", { unique: false });

// 使用邮箱建立索引,我们确保客户的邮箱不会重复,所以我们使用 unique 索引
objectStore.createIndex("email", "email", { unique: true });

// 使用事务的 oncomplete 事件确保在插入数据前对象仓库已经创建完毕
objectStore.transaction.oncomplete = function(event) {
// 将数据保存到新创建的对象仓库
var customerObjectStore = db.transaction("customers", "readwrite").objectStore("customers");
customerData.forEach(function(customer) {
customerObjectStore.add(customer);
});
};
};

开源库

ShareDB

ShareDB 是一个基于 JSON 文档操作转换(OT)的实时数据库后端。它是 DerbyJS Web 应用程序框架的实时后端。

ImmortalDB

ImmortalDB是在浏览器中存储持久键值数据的最佳方法。保存到ImmortalDB的数据被冗余地存储在 Cookies, IndexedDB和 LocalStorage中,并且如果其中的任何数据被删除或损坏,它们将不断进行自我修复。

web-storage-cache

WebStorageCache 对 HTML5 localStorage 和 sessionStorage 进行了扩展,「添加了超时时间,序列化方法」。可以直接存储 JSON 对象,同时可以非常简单的进行超时时间的设置。

lz-string

lz-string 旨在满足在 localStorage 中(尤其是在移动设备上)存储大量数据的需求。localStorage 通常限制为 5MB ~10MB,你可以通过对数据进行压缩,以存储更多的数据。

主流数据库

localForage

localForage 是一个快速简单的 JavaScript 存储库。它通过使用类似于 localStorage 的简单 API 来使用异步存储(IndexedDB 或 WebSQL)),进而改善你的 Web 应用程序的离线体验。

对于不支持 IndexedDB 或 WebSQL 的浏览器,localForage 会使用 localStorage 进行数据存储。此外,localForage 还支持存储所有可以序列化为 JSON 的原生 JS 对象以及 ArrayBuffers,Blob 和 TypedArrays。

PouchDB

PouchDB 是一个浏览器内数据库,允许应用程序在本地保存数据,以便用户即使在离线时也可以享受应用程序的所有功能。另外,数据在客户端之间是同步的,因此用户可以随时随地保持最新状态

Rxdb

RxDB(Reactive Database 的缩写)是 NoSQL 数据库,用于 JavaScript 应用程序,如网站,混合应用程序,Electron Apps,Progressive Web Apps 和 Node.js。响应式意味着你不仅可以查询当前状态,还可以订阅所有状态更改,比如查询的结果或文档的单个字段。

NeDB

NeDB 是一个 JavaScript 数据库,能够运行在 Node.js、nw.js、Electron 和浏览器环境。它是使用纯的 JavaScript 实现,不依赖其它库,提供的 API 是 MongoDB API 的子集,重要的是它的速度非常快:

Dexie.js

Dexie.js 是 IndexedDB 的包装库,它提供了一套经过精心设计的 API,强大的错误处理,较强的可扩展性,此外它能够跟踪数据变化,支持 KeyRange (搜索不区分大小写,可设置匹方式和 OR 操作)。

Lowdb

适用于Node,Electron和浏览器的小型JSON数据库。由Lodash驱动。

Lovefield

Lovefield是用纯JavaScript编写的关系数据库。它提供类似SQL的语法并可以跨浏览器运行(当前支持Chrome 37 +,Firefox 31 +,IE 11 +,Edge和Safari 10+)。

LokiJS

LokiJS是一个以javascript编写的面向文档的数据库,已根据MIT许可证发布。其目的是以nosql方式将javascript对象存储为文档,并以类似的机制对其进行检索。在节点(包括cordova / phonegap和node-webkit),本机 脚本和浏览器中运行。


相关资料
前端存储除了 localStorage 还有啥
浏览器存储
HTTP cookies
Web Storage API
使用 Web Storage API
Window.localStorage
LocalStorage
Window.sessionStorage
IndexedDB


详细
后期用到在看
使用 IndexedDB
浏览器数据库 IndexedDB 入门教程
网道

作者

Fallen-down

发布于

2020-06-29

更新于

2020-06-30

许可协议

You need to set install_url to use ShareThis. Please set it in _config.yml.
You forgot to set the business or currency_code for Paypal. Please set it in _config.yml.

评论

You forgot to set the shortname for Disqus. Please set it in _config.yml.
You need to set client_id and slot_id to show this AD unit. Please set it in _config.yml.