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

前言

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

由於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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章