1. 程式人生 > 實用技巧 >一文梳理Web儲存,從cookie,WebStorage到IndexedDB

一文梳理Web儲存,從cookie,WebStorage到IndexedDB

前言

HTTP是無狀態的協議,網路早期最大的問題之一是如何管理狀態。伺服器無法知道兩個請求是否來自同一個瀏覽器。cookie應運而生,開始出現在各大網站,然而隨著前端應用複雜度的提高,Cookie 也漸漸演化為了一個“儲存多面手”,承載了 自身僅有的4KB 記憶體所不能承受的壓力。在這樣的背景下,web Storage應運而生,專門用於瀏覽器儲存。但web Storage也僅僅是cookie的擴充套件,只能用於儲存少量的簡單資料,當遇到大規模的、結構複雜的資料時,Web Storage 也愛莫能助。這時候,就不得不其強大的IndexedDB了,一個執行在瀏覽器上的非關係型資料庫。本文從cookie講起,Web Storage過渡,IndexedDB結尾,梳理一下web 儲存的體系與知識,希望在幫助作者梳理知識體系的同時也能幫助到廣大前端ers!

cookie

由於http是無狀態的協議,一旦客戶端和伺服器的資料交換完畢,就會斷開連線,再次請求,會重新連線,伺服器單從網路連線上無法知道使用者身份。怎麼辦呢?那就給每次新的使用者請求時,給它頒發一個身份證(獨一無二)吧,下次訪問,必須帶上身份證,這樣伺服器就會知道是誰來訪問了,針對不同使用者,做出不同的響應,這就是Cookie的原理。

Cookie 的本職工作並非本地儲存,而是“維持狀態”。它是瀏覽器儲存在使用者機器的一個小文字檔案大小不能超過4k,並且一些瀏覽器甚至會限制cookie的數量。Cookie是純文字,沒有可執行程式碼。儲存一些伺服器需要的資訊,每次請求站點,會傳送相應的cookie,這些cookie可以用來辨別使用者身份資訊等作用。

cookie的編碼方式為encodeURI()。

cookie型別

cookie按照過期時間分為兩類:會話cookie和持久cookie。

會話cookie是一種臨時cookie,對標session,當使用者退出瀏覽器,會話cookie就會被刪除。預設情況下,即不設定過期時間,設定的cookie為會話cookie。持久cookie則會儲存在硬碟裡,保留時間更長,不以瀏覽器的關閉為轉移,通常是永續性的cookie會維護某一個使用者週期性訪問伺服器的配置檔案或者登入資訊。

cookie的屬性

domain(cookie的域)

產生Cookie的伺服器可以向set-Cookie響應首部新增一個domain屬性來控制哪些站點可以看到那個cookie,例如下面:

Set-Cookie:name="losstie";domain="m.baidu.com"

如果使用者訪問m.baidu.com就會傳送這個cookie,不是則不會。

path(cookie的路徑 )

path 引數告訴瀏覽器 cookie 的路徑。預設情況下,cookie 屬於當前頁面。

secure

設定了屬性secure,cookie只有在https協議加密情況下才會傳送給服務端。但是這並不是最安全的,由於其固有的不安全性,敏感資訊也是不應該通過cookie傳輸的。

HttpOnly

禁止javascript操作cookie(為避免跨域指令碼(xss)攻擊,通過javascript的document.cookie無法訪問帶有HttpOnly標記的cookie。)

SamSite

Cookie 的SameSite屬性用來限制第三方 Cookie,從而減少安全風險。它可以設定三個值:

  • Strict 完全禁止第三方 Cookie,跨站點時,任何情況下都不會傳送 Cookie。換言之,只有當前網頁的 URL 與請求目標一致,才會帶上 Cookie。
  • Lax 規則稍稍放寬,大多數情況也是不傳送第三方 Cookie,但是導航到目標網址的 Get 請求除外。導航到目標網址的 GET 請求,只包括三種情況:連結,預載入請求,GET 表單
  • None Chrome 計劃將Lax變為預設設定。這時,網站可以選擇顯式關閉SameSite屬性,將其設為None。不過,前提是必須同時設定Secure屬性(Cookie 只能通過 HTTPS 協議傳送),否則無效。

cookie操作

通過docuemnt.cookie可以設定和獲取Cookie的值

/* cookie */
function set(key, value){
document.cookie = key + "=" + value;
} function get(key){
var all = document.cookie;
var s = all.indexOf(key)+key.toString().length+1;
var e = all.indexOf(";",s);
return all.substring(s,e); } function remove(key){
var e = "expires=" + new Date(1970,1,1); // 標註過去的時間
document.cookie = key + "=;" + e;
}

第三方cookie

通常cookie的域和瀏覽器地址的域匹配,這被稱為第一方cookie。第三方cookie就是cookie的域和位址列中的域不匹配,這種cookie通常被用在第三方廣告網站。用於跟蹤使用者的瀏覽記錄,並且根據收集的使用者的瀏覽習慣,給使用者推送相關的廣告。

cookie的劣勢

  • Cookie 不夠大,體積不能超過4k,當 Cookie 超過 4KB 時,它將面臨被裁切的命運。這樣看來,Cookie 只能用來存取少量的資訊。
  • 每次都會攜帶在http頭中,過量的cookie會損耗效能。
  • cookie是緊跟域名的,同一個域名下的所有請求,都會攜帶 Cookie。
  • 不夠安全,伺服器沒法分辨使用者和攻擊者,攻擊者可以讀取網路上的其他使用者的資訊,包含HTTP Cookie的全部內容,以便進行中間的攻擊。使用跨站點指令碼技術可以竊取cookie等。

Web Storage

Internet Explorer 8+, Firefox, Opera, Chrome, 和 Safari支援Web 儲存。

Web Storage 是 HTML5 專門為瀏覽器儲存而提供的資料儲存機制。它又分為 Local Storage 與 Session Storage。localStorage與sessionStorage儲存的資料,以“鍵值對”的形式存在,並都是以文字格式儲存。

localStorage與sessionStorage的區別

兩者的區別在於生命週期作用域的不同。

  • 生命週期: Local Storage 是持久化的本地儲存,儲存在其中的資料永遠不會過期,只能是手動刪除。Session Storage 是臨時性的本地儲存,它是會話級別的儲存,當會話結束(頁面被關閉)時,儲存內容也隨之被釋放。
  • 作用域:Local Storage、Session Storage 和 Cookie 都遵循同源策略。但 Session Storage 在遵循同源策略的前提下,還需要在同一視窗。只要它們不在同一個瀏覽器視窗中開啟,那麼它們的 Session Storage 內容便無法共享。

方法

不管是 localStorage,還是 sessionStorage,可使用的API都相同。以localStorage為例:

  • 儲存資料:localStorage.setItem(key,value);
  • 讀取資料:localStorage.getItem(key);
  • 刪除單個資料:localStorage.removeItem(key);
  • 刪除所有資料:localStorage.clear();
  • 得到某個索引的key:localStorage.key(index);
module.exports = {
set:set,
get:get,
remove:remove,
removeAll:removeAll,
each:each
} function set(key ,val){
localStorage.setItem(key, JSON.stringify(val));
}; function get(key){
return JSON.parse(localStorage.getItem(key));
}; function remove(key){
localStorage.removeItem(key);
}; function removeAll(){
localStorage.clear();
}; function each(fn){
pluck(localStorage, function(val, key){
fn(val, key);
return false;
});
} function pluck(obj, fn){
if(isList(obj)) {
for(var i = 0; i<obj.length;i++){
if(fn(obj[i], i)) {
return obj[i];
}
}
} else {
for(var key in obj) {
if(obj.hasOwnProperty(key)){ if(fn(obj[key], key)){ return obj[key];
}
}
}
}
} function isList(val) {
return (val != null && typeof val != 'function' && typeof val.length == 'number')
} function isFunction(val) {
return val && Object.prototype.toString.call(val) === '[object Function]'
} function isObject(val) {
return val && Object.prototype.toString.call(val) === '[object Object]'
}

Web Storage 特點

  • 儲存容量大: Web Storage 根據瀏覽器的不同,儲存容量可以達到 5-10M 之間。Chrome、FireFox、Edge 都是 5M(IE 忽略)。
  • 僅位於瀏覽器端,不與服務端發生通訊。

應用場景

localStorage:

  • 快取靜態資源,比如圖片內容豐富的電商網站會用它來儲存 Base64 格式的圖片字串或者儲存一些不經常更新的 CSS、JS 等靜態資源。
  • 作為前端 DB 的儲存介質

sessionStorage:

  • 用來儲存生命週期和它同步的會話級別的資訊。比如儲存使用者輸入的內容,當頁面重新整理的時候可以立刻顯示出重新整理前的內容

IndexedDB

IndexedDB 是一個執行在瀏覽器上的非關係型資料庫。理論上來說,IndexedDB 是沒有儲存上限的(一般來說不會小於 250M)。它不僅可以儲存字串,還可以儲存二進位制資料。

IndexedDB特點

  • 鍵值對儲存,IndexedDB 內部採用物件倉庫(object store)存放資料。
  • 非同步,ndexedDB 操作時不會鎖死瀏覽器,使用者依然可以進行其他操作(與 LocalStorage 形成對比,後者的操作是同步的)。
  • 支援事務,只要有一步失敗,整個事務就都取消,資料庫回滾到事務發生之前的狀態,不存在只改寫一部分資料的情況。
  • 同源限制,每一個資料庫對應建立它的域名。網頁只能訪問自身域名下的資料庫,而不能訪問跨域的資料庫。
  • 儲存空間大,一般來說不少於 250MB,甚至沒有上限。
  • 支援二進位制儲存,僅可以儲存字串,還可以儲存二進位制資料(ArrayBuffer 物件和 Blob 物件)。

常見操作

IndexedDB大部分操作並不是常用的呼叫方法,返回結果的模式,而是請求——響應的模式。

  • 建立開啟IndexedDB ----window.indexedDB.open("testDB")

  • 關閉IndexedDB----indexdb.close()

  • 刪除IndexedDB----indexedDB.deleteDatabase(indexdb)

應用場景

在 IndexedDB 中,我們可以建立多個資料庫,一個資料庫中建立多張表,一張表中儲存多條資料——這足以 hold 住複雜的結構性資料。

  • 不需要網路連線的離線純應用,比如Todolist這類用來記錄待辦任務型別的應用。
  • 需要儲存大量資料的應用,比如圖書館管理系統這類儲存大量資料的應用;
  • 配合service work構建pwa應用,用於快取網路請求。

cookie/webStorage/IndexedDB區別

小結

瀏覽器儲存、快取技術的出現和發展,為前端應用帶來了無限的轉機,頁面越發複雜,功能越發強大。可以說,現代前端應用,尤其是移動端應用,之所以可以發展到在體驗上叫板 Native 的地步,web儲存功不可沒(還有快取)。

拓展學習

瀏覽器資料庫 IndexedDB 入門教程-阮一峰

深入瞭解瀏覽器儲存--從cookie到WebStorage、IndexedDB

Cookie 的 SameSite 屬性-阮一峰

我遇過的最難的Cookie問題

這一次帶你徹底瞭解Cookie