前端儲存技術Cookie,Storage,IndexedDB

weixin_33872660發表於2019-01-15

轉自前端儲存技術

前言

後端常用資料庫做資料儲存,譬如MySqlMongoDB,快取技術儲存資料,如RedisMemcached

前端儲存資料目前常用的是CookieStorageIndexedDB

Cookie

HTTP Cookie(也叫Web Cookie或瀏覽器Cookie)是伺服器傳送到使用者瀏覽器並儲存在本地的一小塊資料,它會在瀏覽器下次向同一伺服器再發起請求時被攜帶併傳送到伺服器上。通常,它用於告知服務端兩個請求是否來自同一瀏覽器,如保持使用者的登入狀態。Cookie使基於無狀態的HTTP協議記錄穩定的狀態資訊成為了可能。

分類

Cookie總是儲存在客戶端中(早期Java中經常會將CookieSession作為儲存技術進行比較,Session是將資料儲存在伺服器端,大量的資料儲存會增加伺服器的負擔),按在客戶端中的儲存位置,可分為記憶體Cookie和硬碟Cookie
記憶體Cookie由瀏覽器維護,儲存在記憶體中,瀏覽器關閉後就消失了,其存在時間是短暫的。硬碟Cookie儲存在硬碟裡,有一個過期時間,除非使用者手工清理或到了過期時間,硬碟Cookie不會被刪除,其存在時間是長期的。所以,按存在時間,可分為非持久Cookie和持久Cookie

建立Cookie

Set-Cookie響應頭部和Cookie請求頭部節
伺服器使用Set-Cookie響應頭部向使用者代理(一般是瀏覽器)傳送Cookie資訊。一個簡單的Cookie可能像這樣:Set-Cookie: <cookie名>=<cookie值>

伺服器通過該頭部告知客戶端儲存Cookie資訊

瀏覽器環境下獲取非HttpOnly標記的 cookie


var cookies = document.cookie;複製程式碼複製程式碼


Cookie的缺點

Cookie會被附加在每個HTTP請求中,所以無形中增加了流量。由於在HTTP請求中的Cookie是明文傳遞的,所以安全性成問題,除非用HTTPS

Cookie的大小限制在4KB左右,對於複雜的儲存需求來說是不夠用的。

Cookie的簡單封裝

設定Cookie時一般會將路徑和過期時間一併設定,注意過期時間需要轉換成GMT或者UTC

程式碼

(function IIFE(root){
    function getCookie(cname, defaultValue){
        var value = new RegExp('(^|;| )'+cname+'=([^;]*?)(;|$)', 'g').exec(document.cookie);
        console.log('value:', value);
        if(!value) return defaultValue;
        return value[2];
    }
    function setCookie(cname, cvalue, day, path){
        day = day || 1;
        path = path || '/';
        var date = new Date();
        date.setTime(date.getTime() + day * 24 * 60 * 60 * 1000);
        document.cookie = cname+'='+cvalue+'; expires=' + date.toGMTString() + '; path='+path+'; ';
    }
    function deleteCookie(cname){
        setCookie(cname, null, -1);
    }
    root.Util = {
        getCookie: getCookie,
        setCookie: setCookie,
        deleteCookie: deleteCookie,
    }
})(window);複製程式碼複製程式碼

測試結果


Storage

作為 Web Storage API 的介面,Storage 提供了訪問特定域名下的會話儲存(session storage)或本地儲存(local storage)的功能,例如,可以新增、修改或刪除儲存的資料項。

如果你想要操作一個域名的會話儲存(session storage),可以使用 window.sessionStorage如果想要操作一個域名的本地儲存(local storage),可以使用 window.localStorage

sessionStoragelocalStorage的用法是一樣的,區別在於sessionStorage會在會話關閉也就是瀏覽器關閉時失效,而localStorage是將資料儲存在本地,不受關閉瀏覽器影響,除非手動清除資料

相關的api大家可以參考   

developer.mozilla.org/zh-CN/docs/…

程式碼

(function IIFE(){
    if(!window.localStorage){
        alert('your browser is not support localStorage!');
        return;
    }
    function getStorage(sname, defaultValue){
        //result = window.localStorage.sname
        //result = window.localStorage[sname]
        var result = window.localStorage.getItem(sname);
        return result || defaultValue;
    }
    function setStorage(sname, svalue){
        window.localStorage.setItem(sname, svalue);
    }
    function removeItem(sname){
        window.localStorage.removeItem(sname);
    }
    function getKey(keyIndex){
        return window.localStorage.key(keyIndex);
    }
    function getAllKeys(){
        var arr = [];
        for(var i=0;i<window.localStorage.length;i++){
            arr.push(window.localStorage.key(i));
        }
        return arr;
    }
    function clearStorage(){
        window.localStorage.clear();
    }
    function onStorageChange(event){
        console.log(event)
    }
    window.addEventListener('storage', onStorageChange);
    window.Util = {
        getStorage: getStorage,
        setStorage: setStorage,
        removeItem: removeItem,
        getKey: getKey,
        getAllKeys: getAllKeys,
        clearStorage: clearStorage,
    }
})();複製程式碼複製程式碼

測試結果


IndexedDB

隨著瀏覽器的功能不斷增強,越來越多的網站開始考慮,將大量資料儲存在客戶端,這樣可以減少從伺服器獲取資料,直接從本地獲取資料。

現有的瀏覽器資料儲存方案,都不適合儲存大量資料:Cookie 的大小不超過 4KB,且每次請求都會傳送回伺服器;LocalStorage 2.5MB10MB 之間(各家瀏覽器不同),而且不提供搜尋功能,不能建立自定義的索引。所以,需要一種新的解決方案,這就是 IndexedDB 誕生的背景。

通俗地說,IndexedDB 就是瀏覽器提供的本地資料庫,它可以被網頁尾本建立和操作。IndexedDB 允許儲存大量資料,提供查詢介面,還能建立索引。這些都是 LocalStorage 所不具備的。就資料庫型別而言,IndexedDB 不屬於關係型資料庫(不支援 SQL 查詢語句),更接近 NoSQL 資料庫。

IndexedDB相關API可參考

wangdoc.com/javascript/…

程式碼

(function IIFE(){
    if(!window.indexedDB){
        alert('your browser is not support indexedDB!');
        return;
    }
    var request = window.indexedDB.open('person', 1);
    var db;
    request.onerror = function (event) {
        console.log('資料庫開啟報錯');
    };
    request.onsuccess = function (event) {
        db = request.result;
        console.log('資料庫開啟成功');
    };
    request.onupgradeneeded = function(event) {
        console.log('onupgradeneeded...');
        db = event.target.result;
        var objectStore = db.createObjectStore('person', { keyPath: 'id' });
        objectStore.createIndex('name', 'name', { unique: false });
        objectStore.createIndex('email', 'email', { unique: true });
    }
    function add(obj) {
        var request = db.transaction(['person'], 'readwrite')
            .objectStore('person')
            .add(obj)
            //.add({ id: 1, name: 'ccy', age: 18, email: 'test@example.com' });
    request.onsuccess = <span class="hljs-keyword">function</span> (event) {
        console.log(<span class="hljs-string">'資料寫入成功'</span>);
    };
    request.onerror = <span class="hljs-keyword">function</span> (event) {
        console.log(<span class="hljs-string">'資料寫入失敗'</span>);
    }
}
<span class="hljs-keyword">function</span> <span class="hljs-built_in">read</span>(index) {
    var transaction = db.transaction([<span class="hljs-string">'person'</span>]);
    var objectStore = transaction.objectStore(<span class="hljs-string">'person'</span>);
    var request = objectStore.get(index);
    request.onerror = <span class="hljs-keyword">function</span>(event) {
        console.log(<span class="hljs-string">'事務失敗'</span>);
    };

    request.onsuccess = <span class="hljs-keyword">function</span>(event) {
        <span class="hljs-keyword">if</span> (request.result) {
            console.log(<span class="hljs-string">'Name: '</span> + request.result.name);
            console.log(<span class="hljs-string">'Age: '</span> + request.result.age);
            console.log(<span class="hljs-string">'Email: '</span> + request.result.email);
        } <span class="hljs-keyword">else</span> {
            console.log(<span class="hljs-string">'未獲得資料記錄'</span>);
        }
    };
}
<span class="hljs-keyword">function</span> <span class="hljs-function"><span class="hljs-title">readAll</span></span>() {
    var objectStore = db.transaction(<span class="hljs-string">'person'</span>).objectStore(<span class="hljs-string">'person'</span>);
    objectStore.openCursor().onsuccess = <span class="hljs-keyword">function</span> (event) {
        var cursor = event.target.result;
        <span class="hljs-keyword">if</span> (cursor) {
            console.log(<span class="hljs-string">'Id: '</span> + cursor.key);
            console.log(<span class="hljs-string">'Name: '</span> + cursor.value.name);
            console.log(<span class="hljs-string">'Age: '</span> + cursor.value.age);
            console.log(<span class="hljs-string">'Email: '</span> + cursor.value.email);
            cursor.continue();
        } <span class="hljs-keyword">else</span> {
            console.log(<span class="hljs-string">'沒有更多資料了!'</span>);
        }
    };
}
<span class="hljs-keyword">function</span> update(obj) {
    var request = db.transaction([<span class="hljs-string">'person'</span>], <span class="hljs-string">'readwrite'</span>)
        .objectStore(<span class="hljs-string">'person'</span>)
        .put(obj)
        //.put({ id: 1, name: <span class="hljs-string">'李四'</span>, age: 35, email: <span class="hljs-string">'lisi@example.com'</span> });

    request.onsuccess = <span class="hljs-keyword">function</span> (event) {
        console.log(<span class="hljs-string">'資料更新成功'</span>);
    };

    request.onerror = <span class="hljs-keyword">function</span> (event) {
        console.log(<span class="hljs-string">'資料更新失敗'</span>);
    }
}
<span class="hljs-keyword">function</span> remove(index) {
    var request = db.transaction([<span class="hljs-string">'person'</span>], <span class="hljs-string">'readwrite'</span>)
        .objectStore(<span class="hljs-string">'person'</span>)
        .delete(index);

    request.onsuccess = <span class="hljs-keyword">function</span> (event) {
        console.log(<span class="hljs-string">'資料刪除成功'</span>);
    };
}
window.util = {
    add: add,
    <span class="hljs-built_in">read</span>: <span class="hljs-built_in">read</span>,
    <span class="hljs-built_in">read</span>All: <span class="hljs-built_in">read</span>All,
    update: update,
    remove: remove,
}
複製程式碼
複製程式碼

})();複製程式碼複製程式碼

測試結果


後記

瀏覽器儲存技術目前流行的基本就上面介紹的三種,之前出現的webSql由於用方言SQLlite導致無法統一,也就是說這是一個廢棄的標準。

localStorageindexedDB這裡沒有做詳細的介紹,只是簡單的給出示例程式碼做做演示,不熟悉的可以查閱相關API

參考資料

developer.mozilla.org/zh-CN/docs/…
developer.mozilla.org/zh-CN/docs/…
zh.wikipedia.org/wiki/Cookie
www.ruanyifeng.com/blog/2018/0…
wangdoc.com/javascript/…


相關文章