時間:2016-12-12 17:51:30
做者: zhongxiahtml
這裏主要寫的是理論,具體實踐的比較少,後期寫一個實踐教程,內容基本都是從參考文章裏面抄過來的【看完文章,順便寫作下筆記,加深理解。】前端
瀏覽器緩存,也就是客戶端緩存,既是網頁性能優化裏面靜態資源相關優化的一大利器,也是無數web開發人員在工做過程不可避免的一大問題,因此在產品開發的時候咱們老是想辦法避免緩存產生,而在產品發佈之時又在想策略管理緩存提高網頁的訪問速度。java
瞭解瀏覽器的緩存命中原理,是開發web應用的基礎,本文着眼於此,學習瀏覽器緩存的相關知識,總結緩存避免和緩存管理的方法,結合具體的場景說明緩存的相關問題。但願能對有須要的人有所幫助。nginx
瀏覽器在加載資源的時,先根據 http header 判斷它是否命中強緩存.web
命中強緩存:瀏覽器直接從本身緩存中讀取資源,不發送請求到服務器apache
命中協商緩存:將請求返回,但不是返回該資源的數據,而是告訴瀏覽器能夠直接從緩存中加載這個資源。後端
不命中協商緩存:服務器返回該資源數據瀏覽器
共同點:命中,都是從瀏覽器緩存中加載資源
不一樣點:強緩存不發送請求到服務器,協商緩存會發送請求。緩存
必須開啓強緩存,協商緩存纔會起做用性能優化
什麼是協商緩存?
如圖,返回http狀態爲200,size爲 form cache 的就是強緩存
HTTP1.0 時代,Expires 【表示資源過時時間】【緩存過時的下一個時間 必須GMT 格式】
可能存在問題:服務器時間和客戶端時間不一致,所以 HTTP1.1 出了一些 Cache-control
如圖:
HTTP1.1 時代,Cache-control: 過時時間【緩存多少毫秒】
如圖:
例子:
瀏覽器第一次請求資源,服務器在返回的同時,會在 response 的 header 上加上 Expires
瀏覽器收到資源後,把資源和 Expires 一塊兒緩存下來
第二次請求資源時,拿出Expires和當前請求時間比較下,若是還未過時,則直接從緩存中讀取出來,【這個就叫命中緩存】
沒有命中的話,去服務端請求,走協商緩存道路,最後返回時,會返回一個新的 Expires , 瀏覽器在緩存下來。
和 Expires同樣,只是 過時時間=當前時間+Cache-control 的 Max-age 緩存毫秒數
經過代碼的形式,在web服務器的返回響應 header 中添加 Expies, Cache-control
java.util.Date date = new java.util.Date(); response.setDateHeader("Expires",date.getTime()+20000); //Expires:過期期限值 response.setHeader("Cache-Control", "public"); //Cache-Control來控制頁面的緩存與否,public:瀏覽器和緩存服務器均可以緩存頁面信息; response.setHeader("Pragma", "Pragma"); //Pragma:設置頁面是否緩存,爲Pragma則緩存,no-cache則不緩存
設置不緩存
response.setHeader( "Pragma", "no-cache" ); response.setDateHeader("Expires", 0); response.addHeader( "Cache-Control", "no-cache" );//瀏覽器和緩存服務器都不該該緩存頁面信息
讓web服務器在響應資源的時候統一添加Expires和Cache-Control Header
nginx和apache做爲專業的web服務器,都有專門的配置文件,能夠配置expires和cache-control,這方面的知識,若是你對運維感興趣的話,能夠在百度上搜索「nginx 設置 expires cache-control」或「apache 設置 expires cache-control」都能找到很多相關的文章。
強緩存是前端性能優化最有力的工具,沒有之一。
大量的靜態資源網站,必定要利用強緩存,提升響應速度
例子,京東頁面,強緩存到2026年。【這個強緩存能夠有】
使用強緩存後,如何更新網站呢?
給文件加上 hash 值。
知乎上的完美解決方案
https://www.zhihu.com/question/20790576
注意點【強緩存針對靜態資源,動態資源不要,html資源不要。】
強緩存還有一點須要注意的是,一般都是針對靜態資源使用,動態資源須要慎用,除了服務端頁面能夠看做動態資源外,那些引用靜態資源的html也能夠看做是動態資源,若是這種html也被緩存,當這些html更新以後,可能就沒有機制可以通知瀏覽器這些html有更新,尤爲是先後端分離的應用裏,頁面都是純html頁面,每一個訪問地址可能都是直接訪問html頁面,這些頁面一般不增強緩存,以保證瀏覽器訪問這些頁面時始終請求服務器最新的資源
如圖:返回http狀態304,Not Modified
說白了就是瀏覽器本身不肯定,沒有辦法決定,所以要找 服務器商量下。 服務器說能夠,那瀏覽器就直接從本身緩存裏面找出資源, 服務器說你這個不行啊,過時了。 我給你個新的,瀏覽器就拿新的咯。
協商緩存要發請求,全部header都是 response 和 request 一人一個。
協商緩存是利用的是【Last-Modified,If-Modified-Since】和【ETag、If-None-Match】這兩對Header來管理的。
Response Header : Last-Modified, ETag
Request Header : If-Modified-Since , If-None-Match
第一次跟web服務器請求資源時,在 response 的 header 加上 Last-Modified【文件最後修改時間】
瀏覽器收到資源的時候,把資源文件和 Last-Modified 緩存起來
再次請求的時候, 在 Request Header 加上 If-Modified-Since 的 header, 這個值,就是 第一次web服務器返回的 Last-Modified。
web服務器收到以後,判斷 Last-Modified-Since 和 Last-Modified 是否一致,一致則返回 304 Not Modified. 讓瀏覽器去加載緩存裏面的。
不一致的話,返回資源,並返回一個新的 Last-Modified
瀏覽器繼續緩存下來, 而後繼續上面的步驟。
【Last-Modified,If-Modified-Since】都是根據服務器時間返回的header,通常來講,在沒有調整服務器時間和篡改客戶端緩存的狀況下,這兩個header配合起來管理協商緩存是很是可靠的,可是有時候也會服務器上資源其實有變化,可是最後修改時間卻沒有變化的狀況,而這種問題又很不容易被定位出來,而當這種狀況出現的時候,就會影響協商緩存的可靠性。因此就有了另一對header來管理協商緩存,這對header就是【ETag、If-None-Match】。
全部的步驟都是差很少的
發送請求,返回資源的時候,也返回了一個 ETag【文件的Hash值】
瀏覽器緩存資源,並緩存下 ETag
再次請求的時候,Request Header If-None-Match 把上次傳過來的 ETag 傳過去
web服務器,在生成一個資源文件的 ETag, 而後跟傳過來的比較
同樣,返回 304 Not-Modified,瀏覽器從緩存拿
不同, web服務器返回資源,並返回一個新的 ETag, 而後重複上面操做。
強緩存 和 協商緩存的 緩存管理都是同樣的步驟哈。
在分佈式部署的時候,多臺機器的 Last-Modified 必須保持一致,不然協商緩存會出問題。
分佈式部署,不一樣的機器生成的 ETag 都會不同。 而後協商緩存就會出問題。【所以若是沒有搞定ETag 一致,就先關閉掉。】
協商緩存 須要 配合 強緩存使用 【不啓動強緩存,協商緩存也就不起做用】
response header 包含了強緩存的管理 header
若是資源已經被瀏覽器緩存下來,在緩存失效以前,再次請求時,默認會先檢查是否命中強緩存,若是強緩存命中則直接讀取緩存,若是強緩存沒有命中則發請求到服務器檢查是否命中協商緩存,若是協商緩存命中,則告訴瀏覽器仍是能夠從緩存讀取,不然才從服務器返回最新的資源。這是默認的處理方式,這個方式可能被瀏覽器的行爲改變:
勾選這個 disable cache 緩存, 則不會使用緩存