深入了解瀏覽器存儲
前言
隨著移動網路的發展與演化,我們手機上現在除了有原生 App,還能跑「WebApp」——它即開即用,用完即走。一個優秀的 WebApp 甚至可以擁有和原生 App 媲美的功能和體驗。WebApp 優異的性能表現,有一部分原因要歸功於瀏覽器存儲技術的提升。cookie存儲數據的功能已經很難滿足開發所需,逐漸被WebStorage、IndexedDB所取代,本文將介紹這幾種存儲方式的差異和優缺點。
一、Cookie
1.Cookie的來源
Cookie 的本職工作並非本地存儲,而是「維持狀態」。因為HTTP協議是無狀態的,HTTP協議自身不對請求和響應之間的通信狀態進行保存,通俗來說,伺服器不知道用戶上一次做了什麼,這嚴重阻礙了互動式Web應用程序的實現。在典型的網上購物場景中,用戶瀏覽了幾個頁面,買了一盒餅乾和兩瓶飲料。最後結帳時,由於HTTP的無狀態性,不通過額外的手段,伺服器並不知道用戶到底買了什麼,於是就誕生了Cookie。它就是用來繞開HTTP的無狀態性的「額外手段」之一。伺服器可以設置或讀取Cookies中包含信息,藉此維護用戶跟伺服器會話中的狀態。
我們可以把Cookie 理解為一個存儲在瀏覽器里的一個小小的文本文件,它附著在 HTTP 請求上,在瀏覽器和伺服器之間「飛來飛去」。它可以攜帶用戶信息,當伺服器檢查 Cookie 的時候,便可以獲取到客戶端的狀態。
在剛才的購物場景中,當用戶選購了第一項商品,伺服器在向用戶發送網頁的同時,還發送了一段Cookie,記錄著那項商品的信息。當用戶訪問另一個頁面,瀏覽器會把Cookie發送給伺服器,於是伺服器知道他之前選購了什麼。用戶繼續選購飲料,伺服器就在原來那段Cookie里追加新的商品信息。結帳時,伺服器讀取發送來的Cookie就行了。
2.什麼是Cookie及應用場景
Cookie指某些網站為了辨別用戶身份而儲存在用戶本地終端上的數據(通常經過加密)。 cookie是服務端生成,客戶端進行維護和存儲。通過cookie,可以讓伺服器知道請求是來源哪個客戶端,就可以進行客戶端狀態的維護,比如登陸後刷新,請求頭就會攜帶登陸時response header中的set-cookie,Web伺服器接到請求時也能讀出cookie的值,根據cookie值的內容就可以判斷和恢復一些用戶的信息狀態。
如上圖所示,Cookie 以鍵值對的形式存在。
典型的應用場景有:
記住密碼,下次自動登錄。
購物車功能。
記錄用戶瀏覽數據,進行商品(廣告)推薦。
3.Cookie的原理及生成方式
Cookie的原理
第一次訪問網站的時候,瀏覽器發出請求,伺服器響應請求後,會在響應頭裡面添加一個Set-Cookie選項,將cookie放入到響應請求中,在瀏覽器第二次發請求的時候,會通過Cookie請求頭部將Cookie信息發送給伺服器,服務端會辨別用戶身份,另外,Cookie的過期時間、域、路徑、有效期、適用站點都可以根據需要來指定。
Cookie的生成方式主要有兩種:
生成方式一:http response header中的set-cookie
我們可以通過響應頭裡的 Set-Cookie 指定要存儲的 Cookie 值。默認情況下,domain 被設置為設置 Cookie 頁面的主機名,我們也可以手動設置 domain 的值。
當Cookie的過期時間被設定時,設定的日期和時間只與客戶端相關,而不是服務端。
生成方式二:js中可以通過document.cookie可以讀寫cookie,以鍵值對的形式展示
例如我們在掘金社區控制台輸入以下三句代碼,便可以在Chrome 的 Application 面板查看生成的cookie:
從上圖中我們可以得出:
Domain 標識指定了哪些域名可以接受Cookie。如果沒有設置domain,就會自動綁定到執行語句的當前域。如果設置為」.baidu.com」,則所有以」baidu.com」結尾的域名都可以訪問該Cookie,所以在掘金社區上讀取不到第三條代碼存儲Cookie值。
4.Cookie的缺陷
Cookie 不夠大
Cookie的大小限制在4KB左右,對於複雜的存儲需求來說是不夠用的。當 Cookie 超過 4KB 時,它將面臨被裁切的命運。這樣看來,Cookie 只能用來存取少量的信息。此外很多瀏覽器對一個站點的cookie個數也是有限制的。
這裡需注意:各瀏覽器的cookie每一個 的value值大概在4k,所以4k並不是一個域名下所有的cookie共享的,而是一個name的大小。
過多的 Cookie 會帶來巨大的性能浪費
Cookie 是緊跟域名的。同一個域名下的所有請求,都會攜帶 Cookie。大家試想,如果我們此刻僅僅是請求一張圖片或者一個 CSS 文件,我們也要攜帶一個 Cookie 跑來跑去(關鍵是 Cookie 里存儲的信息並不需要),這是一件多麼勞民傷財的事情。Cookie 雖然小,請求卻可以有很多,隨著請求的疊加,這樣的不必要的 Cookie 帶來的開銷將是無法想像的。
cookie是用來維護用戶信息的,而域名(domain)下所有請求都會攜帶cookie,但對於靜態文件的請求,攜帶cookie信息根本沒有用,此時可以通過cdn(存儲靜態文件的)的域名和主站的域名分開來解決。
由於在HTTP請求中的Cookie是明文傳遞的,所以安全性成問題,除非用HTTPS。
5.Cookie與安全
對於 cookie 來說,我們還需要注意安全性。
HttpOnly 不支持讀寫,瀏覽器不允許腳本操作document.cookie去更改cookie,所以為避免跨域腳本 (XSS) 攻擊,通過JavaScript的 Document.cookie API無法訪問帶有 HttpOnly 標記的Cookie,它們只應該發送給服務端。如果包含服務端 Session 信息的 Cookie 不想被客戶端 JavaScript 腳本調用,那麼就應該為其設置 HttpOnly 標記。
標記為 Secure 的Cookie只應通過被HTTPS協議加密過的請求發送給服務端。但即便設置了 Secure 標記,敏感信息也不應該通過Cookie傳輸,因為Cookie有其固有的不安全性,Secure 標記也無法提供確實的安全保障。
為了彌補 Cookie 的局限性,讓「專業的人做專業的事情」,Web Storage 出現了。
HTML5中新增了本地存儲的解決方案----Web Storage,它分成兩類:sessionStorage和localStorage。這樣有了WebStorage後,cookie能只做它應該做的事情了——作為客戶端與伺服器交互的通道,保持客戶端狀態。
二、LocalStorage
1.LocalStorage的特點
保存的數據長期存在,下一次訪問該網站的時候,網頁可以直接讀取以前保存的數據。
大小為5M左右
僅在客戶端使用,不和服務端進行通信
介面封裝較好
基於上面的特點,LocalStorage可以作為瀏覽器本地緩存方案,用來提升網頁首屏渲染速度(根據第一請求返回時,將一些不變信息直接存儲在本地)。
2.存入/讀取數據
localStorage保存的數據,以「鍵值對」的形式存在。也就是說,每一項數據都有一個鍵名和對應的值。所有的數據都是以文本格式保存。存入數據使用setItem方法。它接受兩個參數,第一個是鍵名,第二個是保存的數據。 讀取數據使用getItem方法。它只有一個參數,就是鍵名。
具體步驟,請看下面的例子:
3.使用場景
LocalStorage在存儲方面沒有什麼特別的限制,理論上 Cookie 無法勝任的、可以用簡單的鍵值對來存取的數據存儲任務,都可以交給 LocalStorage 來做。
這裡給大家舉個例子,考慮到 LocalStorage 的特點之一是持久,有時我們更傾向於用它來存儲一些內容穩定的資源。比如圖片內容豐富的電商網站會用它來存儲 Base64 格式的圖片字元串:
三、sessionStorage
sessionStorage保存的數據用於瀏覽器的一次會話,當會話結束(通常是該窗口關閉),數據被清空;sessionStorage 特別的一點在於,即便是相同域名下的兩個頁面,只要它們不在同一個瀏覽器窗口中打開,那麼它們的 sessionStorage 內容便無法共享;localStorage 在所有同源窗口中都是共享的;cookie也是在所有同源窗口中都是共享的。除了保存期限的長短不同,SessionStorage的屬性和方法與LocalStorage完全一樣。
1.sessionStorage的特點
會話級別的瀏覽器存儲
大小為5M左右
僅在客戶端使用,不和服務端進行通信
介面封裝較好
基於上面的特點,sessionStorage 可以有效對錶單信息進行維護,比如刷新時,表單信息不丟失。
2.使用場景
sessionStorage 更適合用來存儲生命周期和它同步的會話級別的信息。這些信息只適用於當前會話,當你開啟新的會話時,它也需要相應的更新或釋放。比如微博的 sessionStorage就主要是存儲你本次會話的瀏覽足跡:
lasturl 對應的就是你上一次訪問的 URL 地址,這個地址是即時的。當你切換 URL 時,它隨之更新,當你關閉頁面時,留著它也確實沒有什麼意義了,乾脆釋放吧。這樣的數據用 sessionStorage 來處理再合適不過。
3.sessionStorage 、localStorage 和 cookie 之間的區別
共同點:都是保存在瀏覽器端,且都遵循同源策略。
不同點:在於生命周期與作用域的不同
作用域:localStorage只要在相同的協議、相同的主機名、相同的埠下,就能讀取/修改到同一份localStorage數據。sessionStorage比localStorage更嚴苛一點,除了協議、主機名、埠外,還要求在同一窗口(也就是瀏覽器的標籤頁)下
生命周期:localStorage 是持久化的本地存儲,存儲在其中的數據是永遠不會過期的,使其消失的唯一辦法是手動刪除;而 sessionStorage 是臨時性的本地存儲,它是會話級別的存儲,當會話結束(頁面被關閉)時,存儲內容也隨之被釋放。
Web Storage 是一個從定義到使用都非常簡單的東西。它使用鍵值對的形式進行存儲,這種模式有點類似於對象,卻甚至連對象都不是——它只能存儲字元串,要想得到對象,我們還需要先對字元串進行一輪解析。
說到底,Web Storage 是對 Cookie 的拓展,它只能用於存儲少量的簡單數據。當遇到大規模的、結構複雜的數據時,Web Storage 也愛莫能助了。這時候我們就要清楚我們的終極大 boss——IndexedDB!
四、IndexedDB
IndexedDB 是一種低級API,用於客戶端存儲大量結構化數據(包括文件和blobs)。該API使用索引來實現對該數據的高性能搜索。IndexedDB 是一個運行在瀏覽器上的非關係型資料庫。既然是資料庫了,那就不是 5M、10M 這樣小打小鬧級別了。理論上來說,IndexedDB 是沒有存儲上限的(一般來說不會小於 250M)。它不僅可以存儲字元串,還可以存儲二進位數據。
1.IndexedDB的特點
鍵值對儲存。
IndexedDB 內部採用對象倉庫(object store)存放數據。所有類型的數據都可以直接存入,包括 JavaScript 對象。對象倉庫中,數據以"鍵值對"的形式保存,每一個數據記錄都有對應的主鍵,主鍵是獨一無二的,不能有重複,否則會拋出一個錯誤。
非同步
IndexedDB 操作時不會鎖死瀏覽器,用戶依然可以進行其他操作,這與 LocalStorage 形成對比,後者的操作是同步的。非同步設計是為了防止大量數據的讀寫,拖慢網頁的表現。
支持事務。
IndexedDB 支持事務(transaction),這意味著一系列操作步驟之中,只要有一步失敗,整個事務就都取消,資料庫回滾到事務發生之前的狀態,不存在只改寫一部分數據的情況。
同源限制
IndexedDB 受到同源限制,每一個資料庫對應創建它的域名。網頁只能訪問自身域名下的資料庫,而不能訪問跨域的資料庫。
儲存空間大
IndexedDB 的儲存空間比 LocalStorage 大得多,一般來說不少於 250MB,甚至沒有上限。
支持二進位儲存。
IndexedDB 不僅可以儲存字元串,還可以儲存二進位數據(ArrayBuffer 對象和 Blob 對象)。
2.IndexedDB的常見操作
在IndexedDB大部分操作並不是我們常用的調用方法,返回結果的模式,而是請求——響應的模式。
建立打開IndexedDB ----
這條指令並不會返回一個DB對象的句柄,我們得到的是一個 對象,而我們希望得到的DB對象在其result屬性中
除了result,IDBOpenDBRequest介面定義了幾個重要屬性:
onerror: 請求失敗的回調函數句柄
onsuccess:請求成功的回調函數句柄
onupgradeneeded:請求資料庫版本變化句柄
控制台得到一個 IDBDatabase對象,這就是IndexedDB對象
關閉IndexedDB----
刪除IndexedDB----
3.WebStorage、cookie 和 IndexedDB之間的區別
從上表可以看到,cookie 已經不建議用於存儲。如果沒有大量數據存儲需求的話,可以使用 localStorage 和 sessionStorage 。對於不怎麼改變的數據盡量使用 localStorage 存儲,否則可以用 sessionStorage 存儲。
總結
正是瀏覽器存儲、緩存技術的出現和發展,為我們的前端應用帶來了無限的轉機。近年來基於存儲、緩存技術的第三方庫層出不絕,此外還衍生出了 PWA 這樣優秀的 Web 應用模型。總結下本文幾個核心觀點:
Cookie 的本職工作並非本地存儲,而是「維持狀態」
Web Storage 是 HTML5 專門為瀏覽器存儲而提供的數據存儲機制,不與服務端發生通信
IndexedDB 用於客戶端存儲大量結構化數據
參考文章
把cookie聊清楚
HTML5本地存儲——IndexedDB(一:基本使用)
詳說 Cookie, LocalStorage 與 SessionStorage
前端性能優化原理與實踐
localstorage 必知必會
瀏覽器資料庫 IndexedDB 入門教程
本文轉載自【Java架構沉思錄】
TAG:程序員之家 |