[譯] 不一樣類型的瀏覽器存儲

現代瀏覽器爲如何在用戶瀏覽器中存儲網站數據提供了多樣的選擇,容許按需查詢這些數據。這使得網站全部者能長期保留數據,保存網頁內容或文檔供離線使用,存儲用戶偏好,應用狀態等。javascript

在本教程中,咱們將討論能夠在用戶瀏覽器上存儲網站數據的不一樣類型的瀏覽器存儲。html

瀏覽器存儲的使用場景

  • 個性化網站偏好
  • 持久化站點活動
  • 存儲登陸狀態
  • 本地保存數據和資源以便快速下載或離線使用
  • 本地保存 Web 應用生成的文檔供離線使用
  • 提高網站性能
  • 減小對後端服務器的請求

瀏覽器存儲的類型

  • Cookies
  • 本地存儲(localStorage)
  • 會話存儲(sessionStorage)
  • IndexedDB
  • Web SQL
  • 緩存存儲(CacheStorage)

Cookies

它是在客戶端存儲數據的傳統方法,由於在 HTML5 出現前,這是瀏覽器存儲的惟一選擇。前端

Cookie 保存客戶端的數據,爲網站訪問者提供個性化的體驗。Cookie 在服務端生成,隨響應發到客戶端,每次請求都會與服務器交換數據。服務器能夠根據 cookie 中的數據向用戶發送個性化的內容。java

Cookie 能夠經過 JavaScript 中的 document.cookie 被建立,更新或讀取。HTTPOnly cookie 標誌可在 JavaScript 中被用於限制 cookie 訪問,從而減小一些安全隱患,如被跨站腳本讀取(這類 cookie 僅供服務器端訪問)。android

Cookie 屬性

Set-Cookie: <cookie-name>=<cookie-value>
Set-Cookie: <cookie-name>=<cookie-value>; Expires=<date>
Set-Cookie: <cookie-name>=<cookie-value>; Max-Age=<non-zero-digit>
Set-Cookie: <cookie-name>=<cookie-value>; Domain=<domain-value>
Set-Cookie: <cookie-name>=<cookie-value>; Path=<path-value>
Set-Cookie: <cookie-name>=<cookie-value>; Secure
Set-Cookie: <cookie-name>=<cookie-value>; HttpOnly

Set-Cookie: <cookie-name>=<cookie-value>; SameSite=Strict
Set-Cookie: <cookie-name>=<cookie-value>; SameSite=Lax
Set-Cookie: <cookie-name>=<cookie-value>; SameSite=None; Secure

// 也能夠同時提供多個屬性,例如:
Set-Cookie: <cookie-name>=<cookie-value>; Domain=<domain-value>; Secure; HttpOnly
複製代碼

Cookie 可分爲兩類:會話期 cookie 和持久性 cookie。ios

會話期 cookiegit

會話期 cookie 不須要指定 ExpiresMax-Age 屬性,在瀏覽器關閉時會被移除。github

持久性 cookie算法

持久性 cookie 指定 ExpiresMax-Age 屬性。Cookie 不會在瀏覽器關閉時過時,可是會在特定的日期(Expires)或時間長度(Max-Age)過時。數據庫

經過在 cookie 頭部中設置 domain 選項,某個域中的 cookie 能夠訪問其餘子域。

Set-Cookie: test=test-value; Domain=example.com - cookie 可用於 example.com 及子域
複製代碼

Cookie 的侷限性

  • 只能存儲 4 KB 的數據,具體限制取決於瀏覽器
  • 一個域下的 cookie 數量有限制,具體取決於瀏覽器(如 20 個)
  • 跨域 cookie 的總數有限制,具體取決於瀏覽器(如 300 個)。一旦達到限制數量,爲存儲新的 cookie,最老的 cookie 將被移除。
  • Cookie 數據在每次請求時都被會發到服務器。這將消耗額外的帶寬並影響性能。
  • 可能被第三方讀取數據(如第三方 cookie)

Cookie 會致使多種安全問題,所以如今建議儘量使用現代化存儲 API。

Web Storage API

Web Storage API 容許 Web 應用在用戶瀏覽器中本地存儲數據。 這個 API 已做爲 HTML5 標準的一部分。

相比 cookie,這類存儲的限制更多 —— 好比, 至少 5 MB(實際大小取決於瀏覽器)。這些信息只在客戶端,不會和服務器共享。服務器沒有任何訪問權限來修改數據。

數據不能在域之間共享,包括子域。每一個源(協議或域的組合)都將有惟一的存儲空間 —— 全部 API 操做都在源對應的存儲空間中執行。

爲了在用戶瀏覽器中存儲數據,Web Storage API 提供了兩個不一樣的對象:sessionStoragelocalStorage

localStorage

localStorage 對象存儲沒有過時日期的數據。這些數據在瀏覽器關閉時不會被刪除,並且在以後的幾天、幾周、幾年內都可用直到被網站或用戶刪除。

sessionStorage

sessionStorage 對象除只存儲一個對話的數據外,與 localStorage 對象一致。 當用戶關閉特定的瀏覽器標籤頁時,對應的數據會被刪除。

Web Storage API 以鍵/值對形式存儲數據。全部數據都存儲爲字符串,全部被添加到存儲空間中的數據會被隱式轉換爲字符串類型。在查詢數據時,它將類型顯式轉換爲所需類型。JSON.parse()JSON.stringify() 方法可用於序列化和反序列化對象數據。

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Strict//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
	<head>
		<title>Browser Storage Demos - Web Storage API </title>	
		
		<script type = "text/javascript"> // 檢查瀏覽器支持狀況 if (typeof(Storage) !== "undefined") { function addToStorage() { // 經過如下任一形式將數據添加至本地存儲 localStorage.setItem("testlocal", "test Local Data"); //localStorage.testlocal= "test Local Data"; // 經過如下任一形式將數據添加至會話存儲 sessionStorage.setItem("testsession", "test Session Data"); //sessionStorage.testsession= "test Session Data"; // 添加 JSON 對象到存儲 var testObject = { 'test1': 1, 'test2': 2, 'test3': 3 }; localStorage.setItem('testObject', JSON.stringify(testObject)); } function removeFromStorage() { // 從本地存儲中移除某鍵/值對 localStorage.removeItem("testlocal"); // 清空存儲 //localStorage.clear(); // 從會話存儲中刪除某鍵/值對 sessionStorage.removeItem("testsession"); //sessionStorage.clear(); } function readDataFromStrage() { // 從本地存儲中讀取數據 document.getElementById("data").innerHTML= "Local Storage Data.."+localStorage.getItem("testlocal")+"<br />"; // 從會話存儲中讀取數據 document.getElementById("data").innerHTML+="Session Storage Data.."+sessionStorage.getItem("testsession")+"<br />"; // 從存儲中獲取 JSON 數據 var retrievedObject = localStorage.getItem('testObject'); document.getElementById("data").innerHTML+="JSON Data From Storage: "+JSON.stringify(retrievedObject); } } else { console.log("No Web Storage support.."); } </script>			
	</head>
	<body>
		Welcome to Browser Storage Demos - Web Storage API	<br/> 

		<p id="data"></p>
                <button onclick = "readDataFromStrage()">Read</button>
                <button onclick = "addToStorage()">Add data </button>
                <button onclick = "removeFromStorage()">Delete data </button>
	</body>
</html> 
複製代碼

Web Storage API 的調用是同步的,所以它們可能會影響 UI 渲染。也由於如此,咱們僅應該使用 Web Storage API 存儲和查詢少許數據。在用戶瀏覽器上使用 Web Storage API 存儲及查詢數據是便捷的 —— 全部現代瀏覽器都支持 Web Storage API。


IndexedDB 存儲

IndexedDB 是一個基於 JavaScript 的面向對象數據庫。IndexedDB 容許你存儲和查詢鍵(主鍵,如 SSN)索引的對象。任何結構化克隆算法支持的對象(如:視頻、圖片)均可以被存儲。IndexedDB 的使用比 Web Storage API 複雜得多。

IndexedDB 是一種在用戶瀏覽器中持久化存儲大量數據的方法。IndexedDB 容許你建立具備不用關心網絡可用性這一高級功能的 Web 應用。這些應用在線、離線均可以工做。IndexedDB 對須要存儲大量數據的應用及工做時不要求網絡持續連通的應用而言很是有用。

IndexedDB API 是異步的,不會阻塞 UI 渲染。這個 API 使用索引以支持對數據的高性能搜索。

建立數據庫模式及對象,打開數據庫鏈接,而後在一系列事務中查詢和更新數據。IndexedDB 容許存儲大量結構化數據。具體大小取決於瀏覽器。

數據庫對源(域/協議/端口)是私有的,所以任何網站不能訪問其餘網站的 IndexedDB 存儲。

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Strict//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
	<head>
		<title>Browser Storage Demos - IndexDB API </title>		
		
		
		<script type = "text/javascript"> // 檢查瀏覽器支持狀況 if (window.indexedDB) { // 示例數據 const customerData = [{ ssn: "444-44-4444", name: "test1", age: 35, email: "test1@company.com" }, { ssn: "555-55-5555", name: "test2", age: 32, email: "test2@home.org" }]; const dbName = "testDB"; var db; // 打開數據庫,若是數據庫不存在,則建立數據庫 // 指定數據庫名稱和版本,若是須要修改數據庫結構,則更新版本號 var request = indexedDB.open(dbName, 2); // 錯誤處理程序 request.onerror = function(event) { console.log("error: "); }; // 成功處理程序 request.onsuccess = function(event) { db = request.result; console.log("success: "+ db); }; // 成功打開數據庫時調用處理程序 // 若是版本不一樣,則更新已有數據庫對象或建立對象 request.onupgradeneeded = function(event) { var db = event.target.result; // 設置鍵生成器(autoIncrement: true),默認不開啓 // 使用主鍵建立 object store var objectStore = db.createObjectStore("customers", { keyPath: "ssn" }); // 定義須要的索引 objectStore.createIndex("name", "name", { unique: false }); objectStore.createIndex("email", "email", { unique: true }); // 向對象添加數據 customerData.forEach(function(customer) { objectStore.add(customer); }); }; function add() { // 查詢特定對象的事務,指定模式 - 只讀,讀寫和版本變動 var transaction = db.transaction(["customers"], "readwrite"); // 當全部數據添加到數據庫時調用處理程序 transaction.oncomplete = function(event) { console.log("Add Completed!"); }; // 錯誤處理程序 transaction.onerror = function(event) { }; const customerDataNew = [{ ssn: "777-77-7777", name: "Test3", age: 32, email: "test3@home.org" }]; // 添加新的客戶數據到 store 中 var objectStore = transaction.objectStore("customers"); customerDataNew.forEach(function(customer) { var request = objectStore.add(customer); request.onsuccess = function(event) { console.log("Data Added..."+event.target.result); }; }); } // 經過主鍵和 delete 方法從 store 中刪除數據 function deleteData() { var request = db.transaction(["customers"], "readwrite") .objectStore("customers") .delete("777-77-7777"); request.onsuccess = function(event) { console.log("Record Deleted!"); }; } // 經過主鍵和 get 方法從 store 中讀取數據 function read() { var transaction = db.transaction(["customers"]); var objectStore = transaction.objectStore("customers"); var request = objectStore.get("444-44-4444"); request.onerror = function(event) { // 處理錯誤! }; request.onsuccess = function(event) { document.getElementById("data").innerHTML = "Name for SSN 444-44-4444 is " + request.result.name; }; } // 經過遊標從 store 中讀取全部數據 function readAll() { var objectStore = db.transaction("customers").objectStore("customers"); console.log(db.transaction("customers")); console.log(objectStore); document.getElementById("data").innerHTML=""; objectStore.openCursor().onsuccess = function(event) { var cursor = event.target.result; // 迭代遊標 if (cursor) { document.getElementById("data").innerHTML+="SSN: " + cursor.key + " Name: " + cursor.value.name +" Age: " + cursor.value.age+"<br />"; cursor.continue(); } else { console.log("No more entries!"); } }; } // 經過主鍵和 put 方法更新已有數據 function update() { var objectStore = db.transaction(["customers"], "readwrite").objectStore("customers"); var request = objectStore.get("444-44-4444"); request.onerror = function(event) { }; request.onsuccess = function(event) { // 獲取當前數據  var data = event.target.result; // 更新值 data.age = 42; // 存儲更新後的對象 var requestUpdate = objectStore.put(data); requestUpdate.onerror = function(event) { // 錯誤 }; requestUpdate.onsuccess = function(event) { console.log("Success - the data is updated!"); }; }; } } else { console.log("No IndexDB support.."); } </script>
		
		
	</head>
	<body>
		Welcome to Browser Storage Demos - IndexDB API	<br/>
		
		<p id="data"></p>
                <button onclick = "read()">Read </button>
                <button onclick = "readAll()">Read all </button>
                <button onclick = "add()">Add data </button>
                <button onclick = "deleteData()">Delete data </button>
		<button onclick = "update()">Update data </button>
	
	</body>
</html>
複製代碼

Web SQL 數據庫

「Web SQL 數據庫是一個用於將數據存儲在數據庫中的 Web API,這些數據庫可使用 SQL 的變體進行查詢。」 —— 維基百科

該規範基於 SQLite。Web SQL 數據庫未被全部瀏覽器支持 —— 該標準已被 W3C 否決,IndexedDB 應該會成爲替代品。

儘管如此,它仍能夠在支持的瀏覽器中使用,如 Safari,Chrome,Opera 及 Edge。

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Strict//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
	<head>
		<title>Browser Storage Demos - Web SQL API </title>	
		
		<script type = "text/javascript"> // 檢查瀏覽器支持狀況 if (window.openDatabase) { var db; function createDBAndTable() { // 打開數據庫,若是不存在,則建立數據庫 - 數據庫名稱,版本,描述和所需存儲空間 db = window.openDatabase('test_db', '1.0', 'Test DB', 1024*1024) // 事務 db.transaction(function (tx) { // 刪除已有的表 tx.executeSql('DROP TABLE IF EXISTS CUSTOMERS'); // 包含必填字段建立新表,定義主鍵 tx.executeSql('CREATE TABLE IF NOT EXISTS CUSTOMERS(SSN TEXT PRIMARY KEY , NAME TEXT,AGE INTEGER ,EMAIL TEXT)', [], function(tx, result) { console.log(result); console.log('Table created Successfully!'); }, errorHandler); }); } function insertData() { db.transaction(function (tx) { // 在表中插入數據,可以使用動態變量 tx.executeSql('INSERT INTO CUSTOMERS(SSN, NAME,AGE,EMAIL) VALUES (?,?,?,?)',["444-44-4444","Bill",35,"bill@company.com"], function(tx,result) { console.log("Record Inserted Successfully "+result.insertId ); },errorHandler); tx.executeSql('INSERT INTO CUSTOMERS(SSN, NAME,AGE,EMAIL) VALUES (?,?,?,?)',["555-55-5555","Test1",32,"test1@company.com"], function(tx,result) { console.log("Record Inserted Successfully "+result.insertId); },errorHandler); }); } function readDataFromDB() { db.readTransaction(function (tx) { // 從表中讀取數據並遍歷行對象 tx.executeSql('SELECT * FROM CUSTOMERS', [], function (tx, results) { var len = results.rows.length, i; document.getElementById("data").innerHTML=""; for (i = 0; i < len; i++) { document.getElementById("data").innerHTML+=" SSN: " +results.rows.item(i).SSN+ " Name: "+results.rows.item(i).NAME+" Age: "+results.rows.item(i).AGE+"<br />"; } },errorHandler); }); } function updateData() { db.transaction(function (tx) { // 更新已有數據 tx.executeSql('UPDATE CUSTOMERS SET AGE=? WHERE SSN=?',[45,"444-44-4444"], function(tx,result) { console.log("Record Updated Successfully" +result); },errorHandler); }); } function deleteData() { db.transaction(function (tx) { // 經過主鍵刪除數據 tx.executeSql('DELETE FROM CUSTOMERS WHERE SSN=?',["444-44-4444"], function(tx,result) { console.log("Record Deleted Successfully" +result); },errorHandler); }); } function errorHandler(transaction, error) { console.log('Oops. Error was '+error.message+' (Code '+error.code+')'); return false; } } else { console.log("No Web SQL API support.."); } </script>			
	</head>
	<body>
		Welcome to Browser Storage Demos - Web SQL API	<br/> 

		<p id="data"></p>
                <button onclick = "createDBAndTable()">Create DB/Table</button>
                <button onclick = "insertData()">Insert data </button>
                <button onclick = "readDataFromDB()">Read data </button>
		<button onclick = "updateData()">Update data </button>
		<button onclick = "deleteData()">Delete data </button>
	</body>
</html>
複製代碼

CacheStorage

「CacheStorage 是一種瀏覽器中的存儲機制,用於存儲和查詢網絡請求和響應。它存儲一對 Request 和 Response 對象,Request 做爲鍵,Response 做爲值。」

—— Chidume NnamdiBits and Pieces 專欄

CacheStorage API 能夠在 Window 上下文(DOM 上下文)中使用,也能夠和 Service Worker API 一塊兒使用以實現離線訪問。在本教程中,咱們將更多地討論 DOM 上下文。

CacheStorage 用於在網站中存儲網絡請求和響應,也能夠做爲存儲工具。例如,咱們能夠存儲個性化數據(如用戶偏好)在緩存中,按需查詢這些數據。put 方法可用於將個性化響應對象存儲在緩存存儲中。

CacheStorage API 容許咱們從跨域網站獲取和緩存數據。CacheStorage API 是異步的,不會阻塞 UI 渲染。CacheStorage 選項是最新加入瀏覽器存儲的,有些瀏覽器仍未支持。

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Strict//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
	<head>
		<title>Browser Storage Demos - Cache Storage API </title>	
		
		<script type = "text/javascript"> // 檢查瀏覽器支持狀況 if('caches' in window) { function add() { // 打開緩存存儲,若是不存在,則新建 caches.open('data_cache').then((cache) => { // 從源服務器獲取 data.json,添加響應到緩存存儲中 // 容許跨域響應緩存 —— 指定完整的請求 URL // Request 對象做爲鍵 cache.add(new Request('/data.json')); var data={foo: "bar"}; // 在緩存前將其餘頭選項加入響應對象 const jsonResponse = new Response(JSON.stringify(data), { headers: { 'content-type': 'application/json' } }); // 將自定義 JSON 數據加入緩存存儲 cache.put('/custom.json', jsonResponse); }).catch((err) => { console.log(err); }); } // 將多個 URL 加入緩存 —— 瀏覽器從源獲取數據 function addAll() { caches.open('data_cache').then((cache) => { const urls = ['/data1.json', '/data2.json','/data3.json']; cache.addAll(urls); }).catch((err) => { console.log(err); }); } // 檢查緩存存儲狀態 function checkCacheStatus() { caches.has('data_cache').then((bool) => { document.getElementById("data").innerHTML = "Cache data_cache is available: " + bool+"<br />"; }).catch((err) => { }) caches.has('teat_cache').then((bool) => { document.getElementById("data").innerHTML += "Cache test_cache is available: " + bool; }).catch((err) => { }) } // 刪除緩存存儲 function deleteCache() { caches.delete('data_cache').then((bool) => { document.getElementById("data").innerHTML = "Cache data_cache is deleted"; }).catch((err) => { }) } // 經過緩存鍵(請求 URL 或對象)從緩存中刪除指定對象 function deleteCacheObject() { caches.open('data_cache').then((cache) => { cache.delete('custom.json'); }).catch((err) => { console.log(err); }); } // 從緩存存儲中獲取全部緩存鍵 function getAllKeys() { caches.open('data_cache').then((cache) => { document.getElementById("data").innerHTML = ""; cache.keys().then(function(keys) { keys.forEach(function(key) { document.getElementById("data").innerHTML += key.url+"<br />"; }); }); }).catch((err) => { console.log(err); }); } // 從緩存存儲中獲取緩存數據 function getCacheData() { caches.open('data_cache').then((cache) => { document.getElementById("data").innerHTML = ""; cache.match('custom.json').then((response)=> { response.json().then(data => { document.getElementById("data").innerHTML = JSON.stringify(data); }); }) }).catch((err) => { console.log(err); }); } } else { console.log("No Cache Storage API support.."); } </script>			
	</head>
	<body>
		Welcome to Browser Storage Demos - Cache Storage API	<br/> 

		<p id="data"></p>
                <button onclick = "add()">Add to Cache </button> 
		<button onclick = "addAll()">Add All</button> 
		<button onclick = "checkCacheStatus()">Cache Status </button>
		<button onclick = "deleteCache()">Delete Cache </button> 
		<button onclick = "deleteCacheObject()">Delete Cache Object</button> 	
		<button onclick = "getAllKeys()">Get All Keys</button>
		<button onclick = "getCacheData()">Get Cache Data</button> 	 		
	</body>
</html>
複製代碼

相關演示參見瀏覽器存儲演示(這個演示是在 Node.js 上使用 Express.js 構建的)。

在用戶瀏覽器上存儲數據有多樣的選擇 —— 根據你的使用場景進行選擇。

你能夠選擇使用 CacheStorage API 存儲供離線訪問的數據,而在存儲大量應用或用戶生成的數據的狀況下,IndexedDB 是更好的選擇。固然,Cookie 仍能夠用於存儲用於服務器識別的小型數據。

本地存儲(localStorage)和會話存儲(sessionStorage)則可用於存儲少許數據。本地存儲和會話存儲的 API 是同步的,所以它們會影響 UI 渲染。但與此同時,它們這兩個 API 易於在項目中使用。

若是發現譯文存在錯誤或其餘須要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可得到相應獎勵積分。文章開頭的 本文永久連接 即爲本文在 GitHub 上的 MarkDown 連接。


掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章
相關標籤/搜索