关于HTTP缓存的故事
最近面試被問到了HTTP緩存的內容,沒有了解過太多,只是在某些文章中看到過,知道強緩存和協商緩存這倆名詞,具體是什么并沒有了解過。
關于前端的緩存其實大致就可以區分為瀏覽器緩存和HTTP緩存,平時可能在業務開發中用到瀏覽器緩存會比較多,今天學習一下HTTP緩存的內容
啥是HTTP緩存
HTTP緩存指的是: 當客戶端向服務器請求資源時,會先抵達瀏覽器緩存,如果瀏覽器有要請求資源的副本,就可以直接從瀏覽器緩存中提取而不是從原始服務器中提取這個資源。
常見的HTTP緩存只能緩存GET請求響應的資源,對于其它類型的響應則無能為力,所以后續說的請求緩存都是指GET請求。
HTTP緩存都是從第二次請求開始的。第一次請求資源時,服務器返回資源,并在response header頭中回傳資源的緩存參數;第二次請求時,瀏覽器判斷這些請求參數,命中強緩存直接200,否則就把請求參數加到request header頭中傳給服務器,看是否命中協商緩存,命中則返回304,否則服務器會返回新的資源。
HTTP緩存的分類
根據是否需要重新向服務器發起請求來分類,可分為(強緩存, 協商緩存)根據是否可以被單個或者多個用戶使用來分類,可分為(私有緩存,共享緩存)強緩存如何生效,不需要再和服務器發生交互,而協商緩存不管是否生效,都需要與服務端發生交互。下面是強緩存和協商緩存的一些對比:
| 緩存存放位置 | 本地瀏覽器 | 本地瀏覽器 |
| HTTP狀態碼 | 200 | 304 |
| 誰來決定 | Pragma Cache-Control Expires | ETag/If-Not-Match Last-Modified/If-Modified- |
| 操作是否有效 | 1、Ctrl + F5強制刷新 —無效 2、F5刷新 -----------------無效 3、 地址欄回車 -----------有效 4、 頁面鏈接跳轉 --------有效 5、新開窗口 ---------------有效 6、前進、后退 ------------有效 | 1、Ctrl + F5強制刷新 —無效 2、F5刷新 -----------------有效 3、 地址欄回車 -----------有效 4、 頁面鏈接跳轉 --------有效 5、新開窗口 --------------有效 6、前進、后退 -----------有效 |
強緩存
強制緩存在緩存數據未失效的情況下(即CaChe-Control的max-age沒有過期或者Expires的緩存時間沒有過期),那么就會直接使用瀏覽器的緩存數據,不會再向服務器發送任何請求。強制緩存生效時,HTTP狀態碼為200。這種方式頁面的加載速度是最快的,性能也不是很好的,但是在這期間,如果服務器端的資源修改了,頁面上是拿不到的,因為它不會再向服務器發請求了。這種情況就是我們在開發中經常遇到的,比如你修改了頁面上的某個樣式,在頁面上刷新了但沒有生效,因為走的是強緩存,所以Ctrl + F5一頓操作之后就好了。跟強制緩存相關的header頭屬性有(Pragma/Cache-Control/Expires)
| Pragma(HTTP/1.0) | no-cache: 不直接使用緩存,根據新鮮度來使用緩存 | 高 | 1、響應頭不支持這個屬性 2、為了兼容HTTP/1.0的客戶端 3、 在HTTP1.1中已被廢棄 |
| Cache-Control(HTTP/1.1) | 1、no-cache: 不直接使用緩存,根據新鮮度來使用緩存 2、 no-store: 不使用緩存,每次都是請求下載新資源 3、max-age: xx秒,緩存時長 4、 public/private: 是否只能被單個用戶使用,默認為private 5、 must-revalidate: 每次訪問需要緩存校驗 | 中 | 1、請求頭和響應頭都支持這個屬性 2、不適用于HTTP/1.0 3、在緩存未失效前,獲取不到修改后的資源 |
| Expires(HTTP/1.0+) | GMT時間 | 低 | 1、服務器和客戶端的時間不一致會出問題 2、適用于HTTP/1.0和HTTP1.1 3、在緩存未失效前,獲取不到修改后的資源 |
這個Pragma和Cache-Control共存時的優先級問題還有點異議,我在不同的文章里發現:有的說Pragma的優先級更高,有的說Cache-Control高。為了搞清楚這個問題,我決定動手操作一波,首先我用nodejs搭建后臺服務器,目的是設置緩存參數,具體代碼如下:
然后再瀏覽器上訪問:http://localhost:8888
第一次訪問時都是從后臺返回的數據:
第二次訪問時:
最終得出結論:
Pragma和Cache-control共存時,Pragma的優先級是比Cache-Control高的。
注意:
在chrome瀏覽器中返回的200狀態會有兩種情況:
1、from memory cache
(從內存中獲取/一般緩存更新頻率較高的js、圖片、字體等資源)
2、from disk cache
(從磁盤中獲取/一般緩存更新頻率較低的js、css等資源)
這兩種情況是chrome自身的一種緩存策略,這也是為什么chrome瀏覽器響應的快的原因。其他瀏覽返回的是已緩存狀態,沒有標識是從哪獲取的緩存。
chrome瀏覽器:
Firefox瀏覽器:
協商緩存
當第一次請求時服務器返回的響應頭中沒有Cache-Control和Expires或者Cache-Control和Expires過期還或者它的屬性設置為no-cache時(即不走強緩存),那么瀏覽器第二次請求時就會與服務器進行協商,與服務端對比判斷資源是否進行了修改更新。如果服務端的資源沒有修改,那么就會返回304狀態碼,告訴瀏覽器可以使用緩存中的數據,這樣就減少了服務器的數據傳輸壓力。如果數據有更新就會返回200狀態碼,服務區就會返回更新后的資源并且將緩存信息一起返回。跟協商緩存相關的header頭屬性有(ETag/If-Not-Match 、Last-Modified/If-Modified-Since) 請求頭和響應頭需要成對出現。
| ETag/If-Not-Match(HTTP/1.1) | 校驗值 | 高 | 1、默認使用hash算法,在分布式環境下可能會出現不同服務器生成的ETag值不一致 2、精確的判斷資源有無被修改,可識別一秒內的修改次數 3、計算ETag需要性能消耗 |
| Last-Modified/If-Modified-Since(HTTP/1.0) | GMT時間 | 低 | 1、只要資源修改,無論內容有無變化,都會將資源返回客戶端 2、以時刻為標識,無法獲取一秒內的修改變化 3、某些服務器不能準確獲取最后的修改時間 |
協商緩存的執行流程是這樣的:當瀏覽器第一次向服務器發送請求時,會在響應頭中返回協商緩存的頭屬性:ETag和Last-Modified,其中ETag返回的是一個hash值,Last-Modified返回的是GMT格式的最后修改時間。然后瀏覽器在第二次發送請求的時候,會在請求頭中帶上與ETag對應的If-Not-Match,其值就是響應頭中返回的ETag的值,Last-Modified對應的If-Modified-Since。服務器在接收到兩個參數后會做比較,如果返回的是304狀態碼,則說明請求的資源沒有修改,瀏覽器可以直接在緩存中取數據,否則,服務器會直接返回數據。
注意:
ETag/If-Not-Match是在HTTP/1.1出現的,主要是解決以下問題:
私有緩存(瀏覽器級緩存)
私有緩存只能用于單獨的用戶:(Cache-Control: Private)
共享緩存(代理級緩存)
共享緩存可以被多個用戶使用: (Cache-Control: Public)
HTTP緩存有什么用
怎么使用HTTP緩存
一般需要緩存的資源有HTML頁面和其它靜態資源
HTML頁面緩存的設置主要是在標簽中嵌入 標簽,這種方式只對頁面有效,對頁面上的資源無效
HTML頁面禁用緩存的設置如下
<meta http-equiv="pragma" content="no-cache"> // 僅在IE瀏覽器才識別的標簽,不一定會在請求字段加上Pragma, 但的確會讓當前頁面每次都發新請求 <meta http-equiv="cache-control" content="no-cache"> // 其它主流瀏覽器識別的標簽 <meta http-equiv="expires" content="0"> // 僅有IE瀏覽器才識別的標簽,該方式僅僅作為指揮IE緩存時間的標識,你并不能在請求或響應報文中找到Expires字段HTML設置緩存如下
<meta http-equiv="Cache-Control" content="max-age=7200"> // 其它主流瀏覽器識別的標簽 <meta http-equiv="Expires" content="Mon, 20 Aug 2021 23:00:00 GMT"> // 僅有IE瀏覽器才識別的標簽靜態資源的緩存一般是在web服務器上配置的,常用的web服務器有: nginx、apache。具體的配置這里不做詳細介紹,大家自行查閱。
不想使用緩存的幾種方式
HTTP緩存需要注意的幾點
例如:
http://www.abc.com/article/a.css?v=2312329
http://www.abc.com/article/a.2312329.css
Vary
vary本身是“變化”的意思,而在http報文中更趨于是“vary from”(與。。。不同)的含義,它表示服務端會以什么基準字段來區分、篩選緩存版本。
在服務端有著這么一個地址,如果是IE用戶則返回針對IE開發的內容,否則返回另一個主流瀏覽器版本的內容。
格式:Vary: User-Agent
知會代理服務器需要以 User-Agent 這個請求首部字段來區別緩存版本,防止傳遞給客戶端的緩存不正確。
Date/Age
響應報文中的 Date 和 Age 字段:區分其收到的資源是否命中了代理服務器的緩存。
Date 理所當然是原服務器發送該資源響應報文的時間(GMT格式),如果你發現 Date 的時間與“當前時間”差別較大,或者連續F5刷新發現 Date 的值都沒變化,則說明你當前請求是命中了代理服務器的緩存。
Age 也是響應報文中的首部字段,它表示該文件在代理服務器中存在的時間(秒),如文件被修改或替換,Age會重新由0開始累計。
瀏覽器緩存
下面說說最常用的瀏覽器緩存有: cookie、sessionStorage、localStorage這三者的主要特征如下:
| cookie | 4KB | 1、兼容各種瀏覽器 2、每次都會和后臺交互 3、可設置過期時間 |
| sessionStorage | 5MB | 1、H5新增特性,不兼容低版本瀏覽器 2、本地存儲,不會每次和后臺交互 3、會話關閉,緩存失效 |
| localStorage | 5MB | 1、H5新增特性,不兼容低版本瀏覽器 2、本地存儲,不會每次和后臺交互 3、本地緩存,除非手動刪除,否則一直存在 |
總結
1、對于強緩存,服務器通知瀏覽器一個緩存時間,在緩存時間內,下次請求,直接用緩存,不在時間內,執行協商緩存策略
2、對于協商緩存,將緩存信息中的ETag和Last-Modified通過請求發送給服務器,由服務器校驗,返回304狀態碼時,瀏覽器直接使用緩存。
總結
以上是生活随笔為你收集整理的关于HTTP缓存的故事的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 前端学习(628):数字类型
- 下一篇: 无法实现的梦想:孤独之旅计划