博客 / 詳情

返回

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

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

作者:Adam Giese

翻譯:瘋狂的技術宅

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

未經允許嚴禁轉載

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

Cookies

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

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

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

什麼時候使用 cookies?

那麼,在哪些情況下你希望獲得 Cookie?最常見的應用場景之一是授權 token 。由於 HttpOnly 標誌為 XSS 攻擊添加了額外的保護層,SameSite 可以防止 CSRF,而 Secure 可以確保你的 cookie 被加密,這使你的身份驗證token 有額外的保護層。

由於 auth token 非常小,因此你無需擔心請求過大。此外由於它們會自動附加到每個請求,因此使用 cookie 可以在服務器上確定用户是否經過身份驗證。這對於服務器呈現的內容非常有用,例如你希望將未經過身份驗證的用户重定向到登錄頁面。

Cookie 的另一個用途是存儲用户的語言代碼。由於你可能希望在大多數請求中訪問用户的語言,因此你可以利用它自動附加。

如何使用 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 文檔來獲取更多信息:

  • Web Storage API
  • HTTP cookies
  • IndexedDB API
  • Cache

本文首發微信公眾號:前端先鋒
歡迎掃描二維碼關注公眾號,每天都給你推送新鮮的前端技術文章

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

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

  • 深入理解Shadow DOM v1
  • 一步步教你用 WebVR 實現虛擬現實遊戲
  • 13個幫你提高開發效率的現代CSS框架
  • 快速上手BootstrapVue
  • JavaScript引擎是如何工作的?從調用棧到Promise你需要知道的一切
  • WebSocket實戰:在 Node 和 React 之間進行實時通信
  • 關於 Git 的 20 個面試題
  • 深入解析 Node.js 的 console.log
  • Node.js 究竟是什麼?
  • 30分鐘用Node.js構建一個API服務器
  • Javascript的對象拷貝
  • 程序員30歲前月薪達不到30K,該何去何從
  • 14個最好的 JavaScript 數據可視化庫
  • 8 個給前端的頂級 VS Code 擴展插件
  • Node.js 多線程完全指南
  • 把HTML轉成PDF的4個方案及實現

  • 更多文章...
user avatar guizimo 頭像 ivyzhang 頭像 ziyeliufeng 頭像 dujing_5b7edb9db0b1c 頭像 codepencil 頭像 flymon 頭像 zhangxishuo 頭像 susouth 頭像 buxia97 頭像 ailim 頭像 huaihuaidedianti 頭像 clearlove07 頭像
23 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.