超越 Cookie:當今的客戶端數據存儲技術

超越 Cookie:當今的客戶端數據存儲

做者:Adam Giese

翻譯:瘋狂的技術宅javascript

原文:https://blog.logrocket.com/be...前端

未經容許嚴禁轉載java

當 cookie 被首次引入時,它是瀏覽器保存數據的惟一方式。以後又有了不少新的選擇:Web Storage API、IndexedDB 和 Cache API。那麼 cookie 死了嗎?咱們來看看這些在瀏覽器中存儲數據的技術。git

Cookies

Cookie 是由服務器發送或在客戶端上設置的信息單位,保存在用戶的本地瀏覽器上。它們會自動附加到每一個請求上。因爲 HTTP 是無狀態協議,所以 cookie 容許將信息存儲在客戶端上,以便將其餘上下文數據傳給該服務器。程序員

Cookie 有一些標誌,對於提升數據的安全性很是有用。 HttpOnly 標誌阻止用 JavaScript 訪問 cookie 的行爲,只有附加在 HTTP 請求上時才能訪問它們。這很是適合防止經過 XSS(跨站點腳本)攻擊形成數據泄露。github

此外,Secure 標誌確保僅在經過 HTTPS 協議發送請求時才發送 cookie。 SameSite 標誌,能夠設置爲 laxstrict(它們的差別看這裏),可用於幫助防止 CSRF(跨站點請求僞造)請求。它告訴瀏覽器只有在請求是與請求者在同一域中的 URL 時才發送 cookie。面試

何時使用 cookies?

那麼,在哪些狀況下你但願得到 Cookie?最多見的應用場景之一是受權 token 。因爲 HttpOnly 標誌爲 XSS 攻擊添加了額外的保護層,SameSite 能夠防止 CSRF,而 Secure 能夠確保你的 cookie 被加密,這使你的身份驗證token 有額外的保護層。算法

因爲 auth token 很是小,所以你無需擔憂請求過大。此外因爲它們會自動附加到每一個請求,所以使用 cookie 能夠在服務器上肯定用戶是否通過身份驗證。這對於服務器呈現的內容很是有用,例如你但願將未通過身份驗證的用戶重定向到登陸頁面。數據庫

Cookie 的另外一個用途是存儲用戶的語言代碼。因爲你可能但願在大多數請求中訪問用戶的語言,所以你能夠利用它自動附加。apache

如何使用 cookies?

前面經討論了要使用 cookie 的緣由,如今來看看你能夠如何使用 cookie。要從服務器上給客戶端設置 cookie,須要在 HTTP 響應中添加 Set-Cookie 標頭。 Cookie 應採用 key=value 的格式。若是你要在 Node.js 程序中設置 cookie,你的代碼可能像下面這樣:

response.setHeader('Set-Cookie', ['user_lang=en-us', 'user_theme=dark_mode']);

這將會設置兩個 cookie:它將 user_lang 設置爲 en-us,將 user_theme 設置爲 dark_mode

Cookie 也能夠由客戶端操縱。要設置 cookie,能夠用 key=value 的格式爲 document.cookie 賦值。若是 key 已存在,則會被覆蓋掉。

document.cookie = 'user_lang=es-es';

若是已經定義了 user_lang,它如今等於es-es

你能夠經過訪問 document.cookie 值來查看全部的 cookie。這將返回一串以分號作分隔的鍵值對。

document.cookie = 'user_lang=en-us';
document.cookie = 'user_theme=light_mode';
console.log(document.cookie); // 'user_lang=en-us; user_theme=light_mode;'

要增長鍵值對的可訪問性,可使用如下函數將此字符串解析爲對象:

const parseCookies = x => x
  .split(';')
  .map(e => e.trim().split('='))
  .reduce((obj, [key, value]) => ({...obj, [key]: value}), {});

If you need to set one of the flags onto your cookie, you can add them after a semicolon. For example, if you’d like to set the Secure and SameSite flags onto your cookie, you would do the following:

若是你須要將其中一個標誌設置到 cookie 上,能夠在分號後添加它們。例如你想在 Cookie 上設置 SecureSameSite 標誌,則能夠執行如下操做:

document.cookie = 'product_ids=123,321;secure;samesite=lax'

因爲 HTTPOnly 的做用是使 cookie 只能在服務器上訪問,所以它只能由服務器添加。

除了這些安全標誌以外,你還能夠設置 Max-Age( cookie 應該保存的秒數)或 Expires(Cookie應該過時的日期)。若是這些都未設置,則 cookie 將跟隨瀏覽器會話的持續時間。若是用戶使用隱身模式,則會在用戶會話關閉時刪除 Cookie。

因爲處理 cookie 的接口不是很友好,因此你可使用諸如 js-cookie 之類的庫來方便對其的操做。

Web Storage API

Web Storage API 是一種在本地存儲數據的新選項。它在 HTML5 中中添加,Web Storage API 包括localStoragesessionStorage。雖然 cookie 一般處理 server/client 通訊,但 Web Storage API 最適用於保存客戶端數據。

咱們已經將 cookie 做爲在本地存儲數據的選項,爲何還須要 Web 存儲?其中一個緣由是:因爲 cookie 會自動添加到每一個 HTTP 請求中,所以請求大小會變得臃腫。因此你能夠用 Web Storage API 存儲比 cookie 更大量的數據。

另外一個優勢是更直觀的 API。若是使用 cookie,你須要手動解析 cookie 字符串來訪問各個鍵。 Web Storage 使這更加容易。若是要設置或獲取值,可使用 setItemgetItem

localStorage.setItem('selected_tab', 'FAQ');
localSTorage.getItem('selected_tab'); // 'FAQ'

鍵和值都必須是字符串。若是你想保存一個對象或數組,能夠在保存時調用 JSON.stringify() 並在讀取時調用 JSON.parse() 來實現。

const product = {
  id: '123',
  name: 'Coffee Beans',
};

localStorage.setItem('cached_product', JSON.stringify(product));
JSON.parse(localStorage.getItem('cached_product'));

local storage 的另外一個用例是在多個選項卡之間同步數據。經過爲 'storage' 事件添加偵聽器,你能夠在另外一個選項卡或窗口中更新數據。

window.addEventListener('storage', () => {
  console.log('local storage has been updated');
});

僅當在另外一個文檔中修改本地或會話存儲時纔會觸發此事件。也就是說,你沒法在當前瀏覽器選項卡中偵聽 storage 的更改。不幸的是,截至撰寫本文時,存儲事件監聽器還沒有在 Chrome 上獲得支持

那麼localStoragesessionStorage 之間有什麼區別呢?與 cookie 不一樣,Web Storage API 沒有過時或最大期限功能。若是使用 localStorage,除非手動刪除,不然數據將無限期保留。你能夠經過運行 localStorage.removeItem('key') 來刪除單個鍵的值,或者經過運行 localStorage.clear() 清除全部數據。

若是使用 sessionStorage,則數據將僅持續到當前會話結束。若是你沒有設置最大時間或過時,它將被視爲與 cookie 保持的方式類似。在任何一種狀況下,若是用戶使用隱身,本地存儲都不會在會話之間保留數據。

IndexedDB

若是 cookie 和 localStorage 都不符合你的要求,還有另外一種選擇:IndexedDB,一個瀏覽器內置的數據庫系統。

localStorage 同步執行全部方法時,IndexedDB 會異步調用它們。這將會容許訪問數據而不會阻塞其他代碼。當你處理大量可能訪問代價高昂的代碼時,這很是有用。

IndexedDB 在其存儲的數據類型方面也具備更大的靈活性。雖然 cookies 和 localStorage 僅限於存儲字符串,但 IndexedDB 能夠存儲能夠經過「結構化克隆算法」複製的任何類型的數據。這包括 ObjectDateFileBlobRegEx 以及更多類型

性能和靈活性增長的缺點是 IndexedDB 的 API 更低級且更復雜。幸運的是有許多庫能夠解決這個問題。

localForage 爲 IndexedDB 提供了一個更簡單的相似 localStorage 的 API。 PouchDB 提供了一個能夠離線的存儲 API,能夠與在線 CouchDB 數據庫同步。 idb 是一個小型庫,具備更簡單的基於 promise 的 API。 Dexie 添加了更強大的查詢 API,同時保持了良好的性能。根據你的使用狀況還有許多選擇。

Cache API

另外一種用於持久數據的專用工具是 Cache API。雖然它最初是爲 service workers 建立的,但它可用於緩存任何網絡請求。 Cache API 公開了 Window.caches,它提供了保存和檢索響應的方法,容許你保存可永遠之後訪問的 RequestsResponses 對。

例如,若是你想在從 API 請求響應以前檢查瀏覽器的緩存以獲取響應,則能夠執行如下操做:

const apiRequest = new Request('https://www.example.com/items');
caches.open('exampleCache') // opens the cache
  .then(cache => {
    cache.match(apiRequest) // checks if the request is cached
      .then(cachedResponse => 
        cachedResponse || // return cachedReponse if available
        fetch(apiRequest) // otherwise, make new request
          .then(response => {
            cache.put(apiRequest, response); // cache the response
            return response;
          })
        })
    .then(res => console.log(res))
})

第一次運行代碼時,它將緩存響應。隨後每次都會緩存請求,而且不會發出網絡請求。

總結

在瀏覽器上存儲數據的每種方法都有其本身的用途。若是信息很小,很敏感,而且可能在服務器上使用,那麼 cookie 就是最佳選擇。若是要保存更大且更不敏感的數據,Web Storage API 多是更好的選擇。

若是你打算存儲大量結構化數據,IndexedDB 很是棒。 Cache API 用於存儲來自 HTTP 請求的響應。根據你的須要,有不少工具可供使用。

其餘資源和擴展閱讀

你能夠經過閱讀 MDN 文檔來獲取更多信息:


本文首發微信公衆號:前端先鋒

歡迎掃描二維碼關注公衆號,天天都給你推送新鮮的前端技術文章

歡迎掃描二維碼關注公衆號,天天都給你推送新鮮的前端技術文章

歡迎繼續閱讀本專欄其它高贊文章:


相關文章
相關標籤/搜索