詳解cookie、session和HTTP緩存

1. cookie

1.1 什麼是 cookie?

HTTP Cookie(也叫Web Cookie或瀏覽器Cookie)是服務器發送到用戶瀏覽器並保存在本地的一小塊數據,它會在瀏覽器下次向同一服務器再發起請求時被攜帶併發送到服務器上。javascript

cookie,指網站爲了辨別用戶身份而儲存在用戶本地終端上的數據。cookie 本質上是 HTTP 的一個內容(請求頭)。
在前端工做中,能夠這麼理解 cookie:php

  • cookie 是瀏覽器訪問服務器後,服務器傳給客戶端的一段數據。
  • 瀏覽器將 cookie 保存下來,通常狀況下不會刪除。
  • 瀏覽器每次訪問返回 cookie 的服務器時,都會在請求頭(請求的第二部分)中帶入這段 cookie

1.2 cookie 的做用

cookie 通常有兩個做用:html

  1. 識別用戶身份
    當瀏覽器 A 首次訪問了 服務器 a.com 以後,a.com 服務器會馬上返回一段數據「uid=1」(cookie)給瀏覽器 A,瀏覽器 A 得到 cookie 以後,將 cookie 保存下來。每個cookie都是不同的。 當瀏覽器 A 再次訪問服務器 a.com 時,會帶上「uid=1」 (cookie), 服務器 a.com 會識別 A 的請求頭中的 cookie,從而區別出瀏覽器 A 的身份。

能夠這麼理解:瀏覽器訪問過服務器以後,服務器就會發送一個特殊的身份信息給瀏覽器。當瀏覽器再次訪問服務器時,會強制要求帶上身份信息,而服務器也能夠經過本身頒發出去的身份信息來識別瀏覽器,而這個身份信息就是cookie。 活生生的例子:前端

學校的門卡:第一次去學校,沒有門卡。而後,學校給發了一個門卡,門卡里面有你的姓名、班級等信息。學校規定,有門卡的必須帶門卡上學,你帶上門卡到學校門口刷卡,學校就能知道你是誰,你來上課了。java

  1. 記錄歷史
    cookie 本質上是一段數據,既然是數據,那麼就能記錄東西。在前端領域中,js 能夠修改存儲在本地中的 cookie,往 cookie 中添加或刪除數據,從而記錄下用戶的操做,如:加入購物車、瀏覽歷史等等。
    因爲瀏覽器不會隨便刪除 cookie,因此下次打開網站的時候,cookie 依然還保存着上次的cookie,就能知道歷史操做。

1.3 cookie 在瀏覽器與服務器之間的交流過程

接下來,以client指代客戶端,server指代服務端,說明一個 cookie 的整個做用機制:node

  1. 產生 cookie:client 第一次訪問 server,server 在響應頭中設置一個 cookie 返回給 client,cookie 的內容爲要保存的數據
  2. 保存 cookie:client 在接收到 server 返回的 cookie 後,將 cookie 保存下來,並給cookie一個有效期,過了有效期,cookie 就會失效。
  3. 傳遞 cookie:client 再次訪問 server 將會在請求頭中帶上保存的 cookie,將 cookie 傳遞到 server
  4. 解析 cookie:server 獲得 client 傳遞的 cookie 以後,會解析 cookie,而後將相應的信息返回給 client
    在 cookie 沒有失效以前,cookie 的使用都是圍繞2,3,4三部分來進行的,第1步通常只須要進行一次。

1.4 cookid 存在的問題:

  1. cookie 基於瀏覽器本地存儲數據,所以,只有在保存了 cookie 的那個瀏覽器上可以使用該 cookie。同一設備不一樣瀏覽器之間,cookie 不通用。
  2. cookie 的存儲大小有限制: 4KB 左右。
  3. cookie 存在C盤的一個文件中,不一樣瀏覽器存儲路勁不同。
  4. cookie 是能夠被用戶手動修改的。
  5. cookie 的有效期:默認有效期20分鐘左右。能夠經過後端強制設置有效期,如自動登陸時間。
  6. cookie 的同源策略:cookie 一樣也有同源策略,不過與 ajax 略微不用。ajax 須要徹底同源,而 cookie 只須要同一父級域名便可。 好比: 請求 qq.com 下的資源時,會帶上 qq.com 對應的 cookie,不會帶上 baidu.com 的 cookie; 請求 v.qq.com 下的資源時,瀏覽器不只會帶上 v.qq.com 的 cookie,還會帶上 qq.com 的cookie。在這裏,qq.com 就是 v.qq.com 的父級域名。
    須要特別注意的一點是:在瀏覽器的認知中,www.qq.com和qq.com是兩個不一樣的域名。所以,www.qq.com 不是 v.qq.com 的父域名,qq.com纔是。

因爲 cookie 是__明文__保存在客戶端的數據,可能會被客戶端修改,存在信息泄露的風險,因此,須要一種比 cookie 更加安全的存儲方式來存儲數據。session 就是解決安全問題的方法。web

2. session

2.1 什麼是 session?

來自維基百科的解釋:ajax

在計算機科學領域來講,尤爲是在網絡領域,會話(session)是一種持久網絡協議,在用戶(或用戶代理)端和服務器端之間建立關聯,從而起到交換數據包的做用機制,session在網絡協議(例如telnet或FTP)中是很是重要的部分。算法

我的理解: session 是一種在服務器端保存數據的機制。服務器經過讀取瀏覽器發送的 cookie 和 服務器端的 session 來交換數據。
不一樣於 cookie,session保存在服務器端,不一樣的語言保存方式不同:後端

  • java,保存於服務器內存中,重啓服務器,session 消失
  • php,保存於服務器文件中,重啓服務器,session 依然存在
  • nodejs,保存於服務器內存中,重啓服務器,sessino 消失

2.2 session 的做用

session 的做用和 cookie 的做用大體相同。最大的不一樣點在於二者的安全性和實現方式。文章下面會介紹。

2.3 session 的實現

依然將客戶端稱爲 client,服務端成爲 server,一塊兒瞭解一下 session 的工做流程:

  1. 產生 sessionID:session 是基於 cookie 的一種方案,因此,首先要產生 cookie。client 第一次訪問 server,server 生成一個隨機數,命名爲 sessionID,並將其放在響應頭裏,以 cookie 的形式返回給 client,client 以處理其餘 cookie 的方式處理這段 cookie。大概是這樣:cookie:sessionID=135165432165
  2. 保存 sessionID: server 將要保存的數據保存在相對應的 sessionID 之下,再將 sessionID 保存到服務器端的特定的保存 session 的內存中(如 一個叫 session 的哈希表)
  3. 使用 session: client 再次訪問 server,會帶上首次訪問時得到的 值爲 sessionID 的cookie,server 讀取 cookie 中的 sessionID,根據 sessionID 到保存 session 的內存尋找與 sessionID 匹配的數據,若尋找成功就將數據返回給 client。

session 與 cookie 的區別

  1. session 在服務器端,cookie 在客戶端。
  2. session 用戶沒法查看和修改,cookie 用戶能夠查看修改。
  3. session 和 cookie 的存儲容量不一樣。
  4. session 的實現依賴於 sessionID,而 sessionID 又存儲在 cookie 上,因此,能夠這麼說:session 是基於 cookie 實現的一種數據存儲方式。

3. localStorage

3.1 localStorage 是什麼?

localStorage 是 HTML5 提供的一個 API。
localStorage 的實質是一個hash(哈希表),是一個存在於瀏覽器上的 hash(哈希表)。 localStorage 提供了幾個 API 來添加、讀取、刪除 localStorage:

  • localStorage.setItem(key,value) 往 hash 中添加 key: value 的數據
localStorage.setItem('姓名','蕭XX')
console.log(localStorage) // Storage {姓名: "蕭XX", length: 1}
複製代碼
  • localStorage.getItem(key) 讀取 hash 中 key 的值
localStorage.getItem('姓名')  // "蕭XX"
複製代碼
  • localStorage.removeItem(key) 刪除 hash 中的 key
localStorage.removeItem('姓名')
console.log(localStorage)  // Storage {length: 0}
複製代碼
  • localStorage.clear() 刪除整個 localStorage
localStorage.clear()
console.log(localStorage)  // Storage {length: 0}
複製代碼

3.2 localStorage 的做用

localStorage 是一個保存於客戶端的哈希表,能夠用來本地保存一些數據。

  1. 變量持久化存儲 js 中的變量都是存在內存中的,一旦刷新頁面,內存釋放以後,全部變量的值所有會被從新初始化。
    而 localStorage 保存在本地,不會由於刷新而釋放,因此,可使用 localStorage 來實現變量的持久化存儲
let a = localStorage.getItem('a')

if(!a){
    a = 0
}else{
    a = (+a) + 1
}
console.log(a)   // 0

localStorage.setItem('a', a)

console.log(localStorage.getItem('a'))  // 0 , 變量 a 被保存到 localStorage 中了

// 刷新頁面,這時候會打印出 兩行 1 ,說明變量 a 的值被讀取以後又從新賦值了
複製代碼

典型應用:
記錄是否提示過:若是不使用localStorage 持久化存儲,每次刷新頁面都會彈出提示

let already = localStorage.getItem('提示')
if(!already){
    alert("這是咱們的提示內容")
    localStorage.setItem('提示'true)
}
複製代碼

3.3 localStorage 的特色

  1. localStorage 與 HTTP 沒有任何關係。
  2. HTTP 不會帶上 localStorage 的值,由於二者沒有一毛錢關係。
  3. 只有相同域名的頁面才能互相讀取 localStorage,同源策略與 cookie 一致
  4. 不一樣的瀏覽器,對每一個域名 localStorage 的最大存儲量的規定不同,超出存儲量會被拒絕。Chrome 10MB 左右
  5. 經常使用場景:記錄一些不敏感的信息(不涉及安全的信息)
  6. localStorage 理論上永久有效,除非用戶清理緩存。

4. sessionStorage(會話存儲)

sessionStorage 的全部性質基本上與 localStorage 一致,惟一的不一樣區別在於:
sessionStorage 的有效期是頁面會話持續,若是頁面會話(session)結束(關閉頁面),sessionStorage 就會消失。而 localStorage 則會一直存在。

5. Cache-Control

5.1 Cache-Control 是什麼?

Cache-Control 通用消息頭被用於在http 請求和響應中經過指定指令來實現緩存機制。緩存指令是單向的, 這意味着在請求設置的指令,在響應中不必定包含相同的指令。

理解:
Cache-Control 第一次請求資源時,將資源緩存下來。告訴瀏覽器再次須要該資源時,不要向服務器請求資源,而是直接使用緩存的資源。Cache-Control 是控制緩存的 HTTP 內容(請求頭/響應頭)。

5.2 Cache-Control 怎麼使用?

Cache-Control 有 2 種使用方式:

  1. 以請求頭形式使用 客戶端能夠在 HTTP 請求中使用 Cache-Control 指令
request.setHeader('Cache-Control','max-age=99999999') // 將這次請求的資源緩存 99999999 秒
複製代碼
  1. 以響應頭形式使用 服務器(node版本)能夠在響應請求時,設置 Cache-Control
response.setHeader('Cache-Control','max-age=99999999')  // 將這次請求的資源緩存 99999999 秒
複製代碼

5.3 Cache-Control 的做用

Cache-Control 使用緩存機制,用來縮短二次訪問的響應時間,提升頁面響應性能,實現web性能優化。

5.4 Cache-Control 的實際使用

  1. 首頁不設置緩存 Cache-COntrol 的緩存時間設置通常都會是一個很長的時間,若是全部頁面所有設置緩存,那麼用戶訪問頁面時,不會向服務器請求任何資源。那麼,若是頁面開發者在用戶緩存的有效期內發佈了新版本,因爲用戶不會請求資源,因此用戶得不到新版本的資源,也就沒法進行版本更新。首頁不使用緩存,就是爲了給更新留下入口。
  2. 緩存更新 在 Cache-Control 的緩存機制是基於 URL 的,只有相同的 URL 纔會使用緩存。那麼,若是想要進行版本更新,讓瀏覽器發起新的資源請求,就只須要改動資源的 URL,瀏覽器就會從新請求資源。
<script src='./js/main.js?v=1.0'></script>  <!-- 第一個版本的js,能夠被緩存 -->  
<script src='./js/main.js?v=1.1'></script>  <!-- 第二個版本的js,瀏覽器會再次請求資源 -->
複製代碼

在真正的開發中,資源版本號通常都是使用摘要算法生成的字符串。(md5算法轉換的字符串)

6. Expires

Expires 是之前版本的緩存控制,若是你設置了 Cache-Control,那麼 Expires 會失效。

Expires 頭指定了一個日期/時間, 在這個日期/時間以後,HTTP響應被認爲是過期的;

Expires 工做原理與 Cache-Control 差很少。區別不一樣的是,Expires 設置的緩存時間是一個時間點,過了這個時間點,緩存就過時。

Expires: Expires 使用的是本地時間,會受本地事件影響。

response.setHeader('Expires: Wed', '21 Oct 2019 07:28:00 GMT')  // Expires 使用格林梅治事件,GMT
複製代碼

Cache-Control 和 Expires ,優先使用 Cache-Control

7. Etag

7.1 Etag 是什麼?

ETag HTTP響應頭是資源的特定版本的標識符。 Etag 是 HTTP 的內容,經過匹配標識符來判斷資源是否須要下載。

7.2 Etag 使用

  1. 瀏覽器第一次訪問服務器資源時,服務器端返回一個 Etag 響應頭,Etag 的值爲資源 MD5 摘要的值(告訴瀏覽器,你此次下載的資源是什麼樣子的)。
  2. 當瀏覽器再次請求資源時,會將 Etag 響應頭的值放在一個 if-None-Match 請求頭之中,發送給服務器(將瀏覽器已經擁有的資源的樣子告訴服務器)
  3. 服務器獲取 if-None-Match 的值,再將該值與請求文件的 md5 值進行匹配,若二者匹配,則返回 304,表明資源沒有改變,不用再次下載。(服務器比對本身的資源的樣子與瀏覽器發送過來的樣子,若是二者一致,就讓瀏覽器用本身的資源,不要再讓服務器發送資源了)

8. last-Modified

last-Modified 是什麼?

The Last-Modified 是一個響應首部,其中包含源頭服務器認定的資源作出修改的日期及時間。

通俗地講:last-Modified 是一個響應頭,它的值是:資源最後一次被修改的時間。

last-Modefied 的使用

  1. 瀏覽器第一次訪問服務器上的某個資源,服務器端返回一個 last-Modefied 響應頭,值爲瀏覽器請求的資源的最後一次修改時間(告訴瀏覽器,服務器最後一次修改資源是何時)
  2. 瀏覽器再次訪問服務器時,會有一個名稱爲 If-Modified-Since 的請求頭,值爲服務器返回的 last-Modified 的值(告訴服務器,瀏覽器獲得的最後一次修改資源時間)
  3. 服務器讀取 If-Modified-Since 的值,將其與自身資源的最後一次修改時間進行比對,若二者一致,就返回 304,表明資源沒有改變過,不用再次下載。(服務器比對雙方的修改時間,若時間一致說明沒有修改過,就讓瀏覽器使用本身的資源,不用再下載資源。)

9. 彩蛋(不依賴 cookie 的 session)

9.1 原理

session 實現關鍵是 sessionID,只須要將 sessionID 傳遞給瀏覽器,瀏覽器在請求的時候再將 sessionID 傳遞給服務器,就能夠實現 session。因此,可使用在 URL 中插入查詢參數的方式來實現 sessionID 的傳遞。

9.2 例子

第一步:服務端(node)直接將 sessionID 用 JSON 傳給前端

let sessionID = Math.random() * 10000000 
response.write(`{"sessionID":${sessionID}}`)
複製代碼

第二步:前端處理:將獲取的 JSON 解析出來,獲取 sessionID,跳轉頁面的時候,將sessionID寫到查詢參數之中

let object = JSON.parse(request.responseText)
// 將 sessionID 存到 localStorage 中備用
localStorage.setItem('sessionID',object.sessionID)
window.location.href = `/?sessionID=${}`
複製代碼

第三步:服務器端獲取查詢參數,使用查詢參數之中的 sessionID 去使用 session

ley sessionID = query.sessionID  // query 爲查詢參數
複製代碼
相關文章
相關標籤/搜索