超越 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
標誌,可以設定為 lax
或 strict
(它們的差異看這裡),可用於幫助防止 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 上設定 Secure
和 SameSite
標誌,則可以執行以下操作:
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 包括localStorage
和 sessionStorage
。雖然 cookie 通常處理 server/client 通訊,但 Web Storage API 最適用於儲存客戶端資料。
我們已經將 cookie 作為在本地儲存資料的選項,為什麼還需要 Web 儲存?其中一個原因是:由於 cookie 會自動新增到每個 HTTP 請求中,因此請求大小會變得臃腫。所以你可以用 Web Storage API 儲存比 cookie 更大量的資料。
另一個優點是更直觀的 API。如果使用 cookie,你需要手動解析 cookie 字串來訪問各個鍵。 Web Storage 使這更加容易。如果要設定或獲取值,可以使用 setItem
或 getItem
。
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 上得到支援。
那麼localStorage
和 sessionStorage
之間有什麼區別呢?與 cookie 不同,Web Storage API 沒有過期或最大期限功能。如果使用 localStorage
,除非手動刪除,否則資料將無限期保留。你可以通過執行 localStorage.removeItem('key')
來刪除單個鍵的值,或者通過執行 localStorage.clear()
清除所有資料。
如果使用 sessionStorage
,則資料將僅持續到當前會話結束。如果你沒有設定最大時間或過期,它將被視為與 cookie 保持的方式相似。在任何一種情況下,如果使用者使用隱身,本地儲存都不會在會話之間保留資料。
IndexedDB
如果 cookie 和 localStorage
都不符合你的要求,還有另一種選擇:IndexedDB,一個瀏覽器內建的資料庫系統。
當 localStorage
同步執行所有方法時,IndexedDB 會非同步呼叫它們。這將會允許訪問資料而不會阻塞其餘程式碼。當你處理大量可能訪問代價高昂的程式碼時,這非常有用。
IndexedDB 在其儲存的資料型別方面也具有更大的靈活性。雖然 cookies 和 localStorage
僅限於儲存字串,但 IndexedDB 可以儲存可以通過“結構化克隆演算法”複製的任何型別的資料。這包括 Object
、 Date
、 File
、 Blob
、 RegEx
以及更多型別。
效能和靈活性增加的缺點是 IndexedDB 的 API 更低階且更復雜。幸運的是有許多庫可以解決這個問題。
localForage
為 IndexedDB 提供了一個更簡單的類似 localStorage
的 API。 PouchDB 提供了一個可以離線的儲存 API,可以與線上 CouchDB 資料庫同步。 idb 是一個小型庫,具有更簡單的基於 promise 的 API。 Dexie 新增了更強大的查詢 API,同時保持了良好的效能。根據你的使用情況還有許多選擇。
Cache API
另一種用於持久資料的專用工具是 Cache API。雖然它最初是為 service workers 建立的,但它可用於快取任何網路請求。 Cache API 公開了 Window.caches
,它提供了儲存和檢索響應的方法,允許你儲存可永遠以後訪問的 Requests
和 Responses
對。
例如,如果你想在從 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 文件來獲取更多資訊:
本文首發微信公眾號:前端先鋒
歡迎掃描二維碼關注公眾號,每天都給你推送新鮮的前端技術文章
歡迎繼續閱讀本專欄其它高贊文章:
- 深入理解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個方案及實現