cookie、sessionStorage和localStorage

我們都知道,作爲一名前端開發,或多或少在開發的過程中因爲各種各樣的需求,需要在前端存儲一些數據,比如登錄驗證,可能會用到cookie,或者localStorage存儲token,然後請求手動帶上。所以我們很需要搞清楚前端存儲有哪些方法,以及我們該如何去使用這些我們已經司空見慣的單詞(Cookie、sessionStorage和localStorage)

cookie

HTTP Cookie,通常直接叫做cookie,最初是在客戶端用於存儲會話信息的。該標準要求服務器對任意HTTP請求發送Set-Cookie HTTP頭作爲響應的一部分,其中包含會話信息。

說的直白一點,一般就是用來登錄驗證,在發送登錄請求的以後,服務端在返回的響應頭中設置Set-Cookie,並設置其值。並且cookie遵循瀏覽器同源策略,在不同源的頁面中是訪問不到當前頁面的cookie的。如果可以的,就能拿到cookie僞造請求進行XSS和CSRF攻擊。
在這裏插入圖片描述
就像上圖所示,在響應頭中有了Set-Cookie,並設置了服務端返回的相應的值,這個時候我們在查看當前頁面的Application中的cookie,發現其中已經有了剛纔返回的cookie。會話cookie一般不會存儲在硬盤裏,而是保存在內存中,如果是設置了過期時間,瀏覽器會把cookie保存在硬盤中。
在這裏插入圖片描述
就上圖中,我們可以看見返回的Set-Cookie中有時間,所以當前返回的cookie是保存在硬盤中的。cookie會隨着頁面發送的請求再帶回到服務端,然後服務端判斷cookie的值,進而判斷當前的登錄狀態。 既然我們剛纔設置的cookie是有有效時間的,所以在有效時間之前,我們不管怎麼操作頁面(關閉標籤頁或者瀏覽器),我們只要打開頁面發送請求,就會默認我們已經是登錄狀態,不需要再次登錄。
在這裏插入圖片描述
上圖就是攜帶cookie的請求,這不是前端手動在請求中攜帶上的,是瀏覽器的自主行爲。

Ajax、Axios以及fetch攜帶cookie情況

剛纔我們說了,只要服務端在請求回來的響應頭中設置了Set-Cookie的值,服務端就在瀏覽器中種下了cookie,以後的每個請求都會攜帶上這個cookie,但是也有個別情況發送的請求是不會默認攜帶cookie。

Cors跨域請求和fetch請求默認是不攜帶cookie的

jQuery中的Ajax請求

我們不管jQuery中發送的jsonp請求,因爲嚴格意義上講,jsonp不算是發送請求後端返回數據的形勢。我們現在只討論發送的json請求。在相同域下,我們發送的Ajax請求⬇️

$.ajax({
  type: 'post',
  url: '/person/detail',
  dataType: 'json',
  data: {
    id: 1
  },
  success: function (res) {},
  error: function(e) {}
})

如果我們請求的是一個不同域下的接口,我們不考慮反向代理的情況,因爲反向代理理論上還是訪問相同域的接口。下面是如果我們使用Cors解決跨域的時候⬇️

$.ajax({
  type: 'post',
  url: '/person/detail',
  dataType: 'json',
  data: {
    id: 1
  },
  xhrFields: {
    withCredentials: true // 如果是Cors解決的跨域,我們請求接口的域和我們頁面所在域是不同域,所以需要添加這個屬性值
  },
  success: function (res) {},
  error: function(e) {}
})

Axios請求

下面是我們在vue或者react庫中經常用到一個請求庫——Axios,Axios發送Cors跨域請求,默認也是不會帶上cookie的⬇️

axios({
  method: 'post',
  url: '/person/detail',
  data: {
    id: 1,
  }
});

上面是正常的同域請求,下面我們來看怎麼發送Cors請求

axios({
  method: 'post',
  url: '/person/detail',
  data: {
    id: 1,
  },
  withCredentials: true, // 設置了這個值,我們我就可以發送Cors請求了,這個值默認不設置的話是false
});

fetch請求

fetch是javascript提供的一個比較底層的API,讓我們可以方便的發起fetch請求,但是fetch請求現在看來,只是一個底層API,雖然相對於原生Ajax請求方便一些,但是Ajax已經被各種庫封裝的很方便使用了,可fetch就相形見絀了。就我們現在來看,fetch不僅僅是在發送Cors請求的時候不懈怠cookie,而是默認情況下,fetch什麼情況都不會從服務端發送或接收任何cookied,我們先來看正常請求⬇️

fetch('/person/detail', {
  method: 'POST',
  body: JSON.stringify({id: 1}),
  headers: {
    'content-type': 'application/json'
  },
})

上面我們就發送了一條fetch請求,然後我們需要請求憑證,需要有cookie怎麼辦呢⬇️

fetch('/person/detail', {
  method: 'POST',
  body: JSON.stringify({id: 1}),
  credentials: 'include', // 強制帶上憑據頭,攜帶上cookie
  headers: {
    'content-type': 'application/json'
  },
})

存儲的數據格式

下面是一個cookie的構成

  1. 名稱: 一個唯一確定 cookie 的名稱。cookie 名稱是不區分大小寫的,所以 myCookie 和 MyCookie
    被認爲是同一個 cookie。然而,實踐中最好將 cookie 名稱看作是區分大小寫的,因爲某些服務器會這樣處理
    cookie。cookie 的名稱必須是經過 URL 編碼的。
  2. 值: 儲存在 cookie 中的字符串值。值必須被 URL 編碼。
  3. 域: cookie 對於哪個域是有效的。所有向該域發送的請求中都會包含這個cookie信息。這個值可以包含子域(subdomain,如
    http://www.wrox.com),也可以不包含它(如.http://wrox.com,則對於
    http://wrox.com的所有子域都有效)。如果沒有明確設定,那麼這個域會被認作來自設置 cookie 的那個域。
  4. 路徑: 對於指定域中的那個路徑,應該向服務器發送 cookie。例如,你可以指定 cookie
    只有從http://www.wrox.com/books/ 中才能訪問,那麼 http://www.wrox.com 的頁面就不會發送
    cookie 信息,即使請求都是來自同一個域的。
  5. 失效時間: 表示 cookie 何時應該被刪除的時間戳(也就是,何時應該停止向服務器發送這個cookie)。默認情況下,瀏覽器會話結束時即將所有 cookie刪除;不過也可以自己設置刪除時間。 這個值是個 GMT 格式的日期(Wdy, DD-Mon-YYYY HH:MM:SSGMT),用於指定應該刪除 cookie 的準確時間。因此,cookie可在瀏覽器關閉後依然保存在用戶的機器上。如果你設置的失效日期是個以前的時間,則 cookie 會被立刻刪除。
  6. 安全標誌: 指定後,cookie 只有在使用 SSL 連接的時候才發送到服務器。例如,cookie 信息只
    能發送給https://www.wrox.com,而 http://www.wrox.com 的請求則不能發送
    cookie。每一段信息都作爲 Set-Cookie 頭的一部分,使用分號加空格分隔每一段,如下例所示。

獲取cookie,更改cookie

我們通過js是很方便獲取cookie的只需要document.cookie,我們就能獲取到當前頁面的cookie。

我們發現我們獲取到的cookie是一長串字符串,而我們在Application看到是已經經過序列化的cookie了。我們既然獲取到了cookie,剩下的就是自己進行序列化處理,操作字符串了,我就不多贅述了。

我們更改cookie的話,如果有相同值,會覆蓋,如果沒有,會創建新的
在這裏插入圖片描述
通過上面我們能知道document.cookie是如何獲取和更改cookie值的,不管cookie保存了什麼,都會跟隨請求一併帶到服務端去。如果我們需要頻繁操作cookie的值,我們可以自己封裝操作cookie的get、set方法。

cookie就這些,畢竟我們現在應該不會大量使用cookie去完成前端數據存儲的工作,一是存儲的數量太小,二是請求都會帶上,浪費帶寬。也因爲請求會帶上cookie,所以中間穿插了一些請求攜帶cookie的點。

Web Storage

Web Storage 克服了由cookie代來的一些限制,當數據需要被嚴格控制在客戶端上時,無須持續地將數據發回服務器。Web Storage的兩個主要目的:

  1. 提供一種在cookie之外的存儲會話數據的途徑;
  2. 提供一種存儲大量可以跨會話存在的數據的機制。

sessionStoragelocalStorage共同的Storage Api

sessionStorage和localStorage同屬於Web Storage,雖然他們的有效時間不同,但是有着相同的方法供開發者使用

// clear方法,可以刪除sessionStorage中所有的值
sessionStorage.clear(); // 清除所有sessionStorage中的數據
localStorage.clear(); // 清除所有localStorage中的數據

// getItem(name) 根據指定的名字name獲取對應的值
var name = sessionStorage.getItem('name'); // 獲取key爲name的value
var name = localStorage.getItem('name'); // 獲取key爲name的value
// 當然,我們也可以不這麼着獲取storage中的值,也可以像下面這樣獲取值
var name = sessionStorage.name; // 獲取key爲name的value
var name = localStorage.name; // 獲取key爲name的value

// key(index) 可以獲取到index位置處的值的名字
var key = sessionStorage.key(0); // 獲取到了sessionStorage中排在第一個的值的key,比如剛纔的’name‘
var key = localStorage.key(0); // 獲取到了localStorage中排在第一個的值的key,比如剛纔的’name‘
// 獲取到了排在第一位的key值,我們就可以根據這個key獲取對應的value了
var value = sessionStorage.getItem(key); // 這樣我們就獲取到了排在第一位的name的value值
var value = localStorage.getItem(key); // 這樣我們就獲取到了排在第一位的name的value值

// removedItem(name) 刪除由name指定的鍵值對
sessionStorage.removedItem('name'); // 刪除了key爲name的value
localStorage.removedItem('name'); // 刪除了key爲name的value
// 我們也能使用刪除對象中屬性的delete方法來刪除
delete sessionStorage.name;
delete localStorage.name;

// setItem(name, value) 爲指定的name設置一個對應的值
sessionStorage.setItem('name', 'zhanwuzha'); // 在sessionStorage中存了一個name,值爲zhanwuzha
localStorage.setItem('name', 'zhanwuzha'); // 在localStorage中存了一個name,值爲zhanwuzha
// 我們也可以使用另一種方法來設置
sessionStorage.name = 'zhanwuzha'; // 在sessionStorage中存了一個name,值爲zhanwuzha
localStorage.name = 'zhanwuzha'; // 在localStorage中存了一個name,值爲zhanwuzha

以上就是Web Storage中的方法,涵蓋了增刪改查。delete操作符在WebKit中無法刪除數據,所以我們還是使用removeItem()方法吧;

Web Storage中保存的數據,不會跟隨請求一同發回服務器,這是跟cookie最大的區別,並且是按鍵值對來保存數據的,雖然cookie也是鍵值對,但是是類似'name=zhanwuzha&age=16'這樣的字符串,還需要在進一步處理。

sessionStorage

sessionStorage對象存儲特定於某個會話的數據,也就是該數據只保持到瀏覽器關閉。這個對象就像會話cookie,也會在瀏覽器關閉後消失。存儲在sessionStorage中的數據可以跨越頁面的刷新而存在,同時如果瀏覽器支持,瀏覽器崩潰並重啓之後依然可用(Firefox和WebKit都支持,IE則不行)

sessionStorage在滿足上面storage共同的方法之外,它的使用是綁定在某個會話的:

  • 遵循瀏覽器的同源策略,不同源的根本就訪問不到

  • 符合同源策略的,必須是同一個會話即使是相同地址,不是同一個會話也不行

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章