天天看點

浏覽器存儲

随着移動網絡的發展與演化,我們手機上現在除了有原生 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 的值。

Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2018 07:28:00 GMT;//可以指定一個特定的過期時間(Expires)或有效期(Max-Age)      

當Cookie的過期時間被設定時,設定的日期和時間隻與用戶端相關,而不是服務端。

  • 生成方式二:js中可以通過document.cookie可以讀寫cookie,以鍵值對的形式展示

例如我們在掘金社群控制台輸入以下三句代碼,便可以在Chrome 的 Application 面闆檢視生成的cookie:

document.cookie="userName=hello"      
document.cookie="gender=male"      
document.cookie='age=20;domain=.baidu.com'      
浏覽器存儲

從上圖中我們可以得出:

Domain 辨別指定了哪些域名可以接受Cookie。如果沒有設定domain,就會自動綁定到執行語句的目前域。

如果設定為”.baidu.com”,則所有以”baidu.com”結尾的域名都可以通路該Cookie,是以在掘金社群上讀取不到第三條代碼存儲Cookie值。

4.Cookie的缺陷

  • Cookie 不夠大

Cookie的大小限制在4KB左右,對于複雜的存儲需求來說是不夠用的。當 Cookie 超過 4KB 時,它将面臨被裁切的命運。這樣看來,Cookie 隻能用來存取少量的資訊。此外很多浏覽器對一個站點的cookie個數也是有限制的。

這裡需注意:各浏覽器的cookie每一個name=value的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 标記。

Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; 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方法。它接受兩個參數,第一個是鍵名,第二個是儲存的資料。

localStorage.setItem("key","value");

讀取資料使用getItem方法。它隻有一個參數,就是鍵名。

var valueLocal = localStorage.getItem("key");

具體步驟,請看下面的例子:

<script>
if(window.localStorage){
  localStorage.setItem('name','world')
  localStorage.setItem(“gender','female')
}
</script>      
<body>
<div id="name"></div>
<div id="gender"></div>
<script>
var name=localStorage.getItem('name')
var gender=localStorage.getItem('gender')
document.getElementById('name').innerHTML=name
document.getElementById('gender').innerHTML=gender
</script>
</body>      

3.使用場景

LocalStorage在存儲方面沒有什麼特别的限制,理論上 Cookie 無法勝任的、可以用簡單的鍵值對來存取的資料存儲任務,都可以交給 LocalStorage 來做。

這裡給大家舉個例子,考慮到 LocalStorage 的特點之一是持久,有時我們更傾向于用它來存儲一些内容穩定的資源。比如圖檔内容豐富的電商網站會用它來存儲 Base64 格式的圖檔字元串:

浏覽器存儲

三、sessionStorage

sessionStorage儲存的資料用于浏覽器的一次會話,當會話結束(通常是該視窗關閉),資料被清空;sessionStorage 特别的一點在于,即便是相同域名下的兩個頁面,隻要它們不在同一個浏覽器視窗中打開,那麼它們的 sessionStorage 内容便無法共享;localStorage 在所有同源視窗中都是共享的;cookie也是在所有同源視窗中都是共享的。除了儲存期限的長短不同,SessionStorage的屬性和方法與LocalStorage完全一樣。

1.sessionStorage的特點

  • 會話級别的浏覽器存儲

基于上面的特點,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 ----window.indexedDB.open("testDB")

這條指令并不會傳回一個DB對象的句柄,我們得到的是一個IDBOpenDBRequest對象,而我們希望得到的DB對象在其result屬性中

浏覽器存儲

除了result,IDBOpenDBRequest接口定義了幾個重要屬性:

onerror: 請求失敗的回調函數句柄

onsuccess:請求成功的回調函數句柄

onupgradeneeded:請求資料庫版本變化句柄

<script>
function openDB(name){
var request=window.indexedDB.open(name)//建立打開IndexedDB
request.onerror=function (e){
console.log('open indexdb error')
}
request.onsuccess=function (e){
myDB.db=e.target.result//這是一個 IDBDatabase對象,這就是IndexedDB對象
console.log(myDB.db)//此處就可以擷取到db執行個體
}
}
var myDB={
name:'testDB',
version:'1',
db:null
}
openDB(myDB.name)
</script>      

控制台得到一個 IDBDatabase對象,這就是IndexedDB對象

浏覽器存儲
  • 關閉IndexedDB----indexdb.close()
function closeDB(db){
    db.close();
}      
  • 删除IndexedDB----window.indexedDB.deleteDatabase(indexdb)
function deleteDB(name) {
  indexedDB.deleteDatabase(name)
}      

3.WebStorage、cookie 和 IndexedDB之間的差別

總結

  • Cookie 的本職工作并非本地存儲,而是“維持狀态”
  • Web Storage 是 HTML5 專門為浏覽器存儲而提供的資料存儲機制,不與服務端發生通信
  • IndexedDB 用于用戶端存儲大量結構化資料