目錄
Cookie
簡介
Cookie 的本職工作並非本地存儲,而是“維持狀態”。因為HTTP協議是無狀態的,HTTP協議自身不對請求和響應之間的通信狀態進行保存,,通俗來說,服務器不知道用戶上一次做了什么,這嚴重阻礙了交互式Web應用程序的實現。在典型的網上購物場景中,用戶瀏覽了幾個頁面,買了一盒餅干和兩瓶飲料。最后結帳時,由於HTTP的無狀態性,不通過額外的手段,服務器並不知道用戶到底買了什么,於是就誕生了Cookie。它就是用來繞開HTTP的無狀態性的“額外手段”之一。服務器可以設置或讀取Cookies中包含信息,借此維護用戶跟服務器會話中的狀態。 我們可以把Cookie 理解為一個存儲在瀏覽器里的一個小小的文本文件,它附着在 HTTP 請求上,在瀏覽器和服務器之間“飛來飛去”。它可以攜帶用戶信息,當服務器檢查 Cookie 的時候,便可以獲取到客戶端的狀態。 在剛才的購物場景中,當用戶選購了第一項商品,服務器在向用戶發送網頁的同時,還發送了一段Cookie,記錄着那項商品的信息。當用戶訪問另一個頁面,瀏覽器會把Cookie發送給服務器,於是服務器知道他之前選購了什么。用戶繼續選購飲料,服務器就在原來那段Cookie里追加新的商品信息。結帳時,服務器讀取發送來的Cookie就行了。
使用場景
- 記住密碼,下次自動登錄
- 購物車功能
- 記錄用戶瀏覽數據,進行商品(廣告)推薦
原理
第一次訪問網站的時候,瀏覽器發出請求,服務器響應請求后,會在響應頭里面添加一個Set-Cookie選項,將cookie放入到響應請求中,在瀏覽器第二次發請求的時候,會通過Cookie請求頭部將Cookie信息發送給服務器,服務端會辨別用戶身份,另外,Cookie的過期時間、域、路徑、有效期、適用站點都可以根據需要來指定
讀寫操作
操作瀏覽器對象
//設置 //設置cookie document.cookie = "userId=nick123" //設置過期時間 document.cookie = "userId=nick123; expires=Wed, 15 Jan 2020 12:00:00 UTC" //設置所屬路徑,默認當前頁面路徑 document.cookie = "userId=nick123; expires=Wed, 15 Jan 2020 12:00:00 UTC; path=/user" //設置cookie域 document.cookie = "userId=nick123; expires=Wed, 15 Jan 2020 12:00:00 UTC; path=/user; domain=mysite.com" //讀取 //獲取所有cookie const cookies = document.cookie //使用正則讀取指定名稱的cookie function getCookieValue(name) { let result = document.cookie.match("(^|[^;]+)\\s*" + name + "\\s*=\\s*([^;]+)") return result ? result.pop() : "" } //不使用正則讀取指定cookie function getCookieValue(name) { const nameString = name + "=" const value = document.cookie.split(";").filter(item => { return item.includes(nameString) }) if (value.length) { return value[0].substring(nameString.length, value[0].length) } else { return "" } } //修改 //已覆蓋的方式修改 document.cookie = "userId=new_value" //刪除 document.cookie = "userId=; expires=Thu, 01 Jan 1970 00:00:00 UTC;"
使用npm庫
npm i js-cookie -S import Cookies from 'js-cookie' //設置cookie Cookies.set('foo', 'bar') //設置過期時間 Cookies.set('name', 'value', { expires: 7 }) //設置所屬路徑 Cookies.set('name', 'value', { expires: 7, path: '' }) //讀取 Cookies.get('name') //讀取所有 Cookies.get() //讀取所屬域下的cookie Cookies.get('foo', { domain: 'sub.example.com' }) //刪除 Cookies.remove('name')
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
Cookie與安全
屬性 作用 value 如果用於保存用戶登錄狀態,應該要將該字段加密,不能使用明文的用戶標識 http-only 不能通過js訪問Cookie,減少XSS攻擊 secure 只能在協議為https的請求中攜帶 same-site 規定瀏覽器不能在跨域請求中攜帶Cookie,減少CSRF攻擊
LocalStorage
特點
- 保存的數據長期存在(直到清除瀏覽器的緩存),下一次訪問該網站的時候,網頁可以直接讀取以前保存的數據
- 大小為5M左右
- 僅在客戶端使用,不和服務端進行通信
- 接口封裝較好
使用場景
LocalStorage可以作為瀏覽器本地緩存方案,用來提升網頁首屏渲染速度(根據第一請求返回時,將一些不變信息直接存儲在本地)
讀寫操作
localStorage.setItem(key,value) 保存數據 localStorage.getItem(key) 獲取數據 localStorage.removeItem(key) 刪除數據 localStorage.clear(); 刪除全部數據
sessionStorage
簡介
sessionStorage保存的數據用於瀏覽器的一次會話,當會話結束(通常是該窗口關閉),數據被清空;sessionStorage 特別的一點在於,即便是相同域名下的兩個頁面,只要它們不在同一個瀏覽器窗口中打開,那么它們的 sessionStorage 內容便無法共享;localStorage 在所有同源窗口中都是共享的;cookie也是在所有同源窗口中都是共享的。除了保存期限的長短不同,SessionStorage的屬性和方法與LocalStorage完全一樣
特點
- 會話級別的瀏覽器存儲
- 大小為5M左右
- 僅在客戶端使用,不和服務端進行通信
- 接口封裝較好
使用場景
有效對表單信息進行維護,比如刷新時,表單信息不丟失
讀寫操作
sessionStorage.setItem(key,value) 保存數據 sessionStorage.getItem(key) 獲取數據 sessionStorage.removeItem(key) 刪除數據 sessionStorage.clear(); 刪除全部數據
sessionStorage 、localStorage 和 cookie 之間的區別
- 共同點
都是保存在瀏覽器端,且都遵循同源策略
- 只能存儲字符串
- 不同點
生命周期
- localStorage 是持久化的本地存儲,存儲在其中的數據是永遠不會過期的,使其消失的唯一辦法是手動刪除
- sessionStorage 是臨時性的本地存儲,它是會話級別的存儲,當會話結束(頁面被關閉)時,存儲內容也隨之被釋放
作用域
- localStorage只要在相同的協議、相同的主機名、相同的端口下,就能讀取/修改到同一份localStorage數據
- sessionStorage比localStorage更嚴苛一點,除了協議、主機名、端口外,還要求在同一窗口(當前同一個源下面的只要有一個窗口沒關或者跳到另外的窗口,sessionStorage都會存在)下
Web Storage 是一個從定義到使用都非常簡單的東西,它使用鍵值對的形式進行存儲,這種模式有點類似於對象,卻甚至連對象都不是——它只能存儲字符串,要想得到對象,我們還需要先對字符串進行一輪解析。Web Storage 是對 Cookie 的拓展,它只能用於存儲少量的簡單數據。當遇到大規模的、結構復雜的數據時,Web Storage 也愛莫能助了。這時候我們就要清楚我們的終極大 boss——IndexedDB
IndexedDB
簡介
indexedDB是一個運行在瀏覽器上的非關系型數據庫,沒有存儲上線,一般不會小於250M,它不僅可以儲存字符串,還可以儲存二進制數據。
IndexedDB的特點
- 鍵值對存儲
IndexedDB 內部采用對象倉庫(object store)存放數據。所有類型的數據都可以直接存入,包括 JavaScript 對象。對象倉庫中,數據以"鍵值對"的形式保存,每一個數據記錄都有對應的主鍵,主鍵是獨一無二的,不能有重復,否則會拋出一個錯誤
- 異步
IndexedDB 操作時不會鎖死瀏覽器,用戶依然可以進行其他操作,這與 LocalStorage 形成對比,后者的操作是同步的。異步設計是為了防止大量數據的讀寫,拖慢網頁的表現
- 支持事務
IndexedDB 支持事務(transaction),這意味着一系列操作步驟之中,只要有一步失敗,整個事務就都取消,數據庫回滾到事務發生之前的狀態,不存在只改寫一部分數據的情況。
- 同源限制
IndexedDB 受到同源限制,每一個數據庫對應創建它的域名。網頁只能訪問自身域名下的數據庫,而不能訪問跨域的數據庫
- 儲存空間大
IndexedDB 的儲存空間比 LocalStorage 大得多,一般來說不少於 250MB,甚至沒有上限
- 支持二進制儲存
IndexedDB 不僅可以儲存字符串,還可以儲存二進制數據(ArrayBuffer 對象和 Blob 對象)
IndexedDB的常見操作
- 建立打開IndexedDB ----
window.indexedDB.open("testDB")
function openDB(name) { var request = window.indexedDB.open(name) //建立打開IndexedDB console.log('request', request) 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)
- 關閉IndexedDB----
indexdb.close()
function closeDB(db){ db.close(); }
- 刪除IndexedDB----
window.indexedDB.deleteDatabase(indexdb)
function deleteDB(name) { indexedDB.deleteDatabase(name) }
總結
- Cookie 的本職工作並非本地存儲,而是“維持狀態”
- Web Storage 是 HTML5 專門為瀏覽器存儲而提供的數據存儲機制,不與服務端發生通信
- IndexedDB 用於客戶端存儲大量結構化數據
參考
https://www.jianshu.com/p/8e86bf912b0e
https://juejin.im/post/5d8c33cb5188255a12365056