web缓存细说
web瀏覽器緩存
沒有緩存的世界,每次請求都是嚴格意義上的新的請求,那么服務器端的壓力可想而知,客戶端的響應速度也是大打折扣,就是我們在寫程序也知道需要緩存,把一些常用的數據緩存區來,避免每次都要重新讀取,特別是前端在進行元素獲取時,雖然鏈式調用讓我們很舒服,但是如果每次都需要重新獲取這個元素的話,最好還是使用變量緩存起來比較好。
設置緩存
目前比較常見的緩存機制包括以下幾種[都是設置http header]:
Expires
Cache-Control
Last-Modified/If-Modified-Since:Last-Modified/If-Modified-Since要配合Cache-Control使用。
Etag/If-None-Match:Etag/If-None-Match也要配合Cache-Control使用
一個實際資源訪問的響應頭部部分信息如下:
Expires
Expires是http1.0提出的一個表示資源過期時間的header,它描述的是一個絕對時間,由服務器返回,用GMT格式的字符串表示,如:Expires:Thu, 31 Dec 2016 23:55:55 GMT,
new Date() Sat Aug 05 2017 21:39:11 GMT+0800 (CST) //東八區,使用toUTCString轉換為GMT格式 new Date().toUTCString() "Sat, 05 Aug 2017 13:43:39 GMT" //格林威治時區 0這個時候,發現有個問題,因為時間是服務端返回的,也就是說前端其實很少自己來設置緩存頭部的,node作為后端時例外,問題是如果前后端存在時差,或者時間不一致的時候,只能抓瞎了,誤差會比較大,這個時候第二種方案出來了;
Cache-Control
Cache-Control描述的是一個相對時間,在進行緩存命中的時候,都是利用客戶端時間進行判斷,所以相比較Expires,Cache-Control的緩存管理更有效,安全一些。
讀取緩存數據條件:上次緩存時間(客戶端的)+max-age < 當前時間(客戶端的)Cache-Control值可以是public、private、no-cache、no- store、no-transform、must-revalidate、proxy-revalidate、max-age
各個消息中的指令含義如下: Public指示響應可被任何緩存區緩存。 Private指示對于單個用戶的整個或部分響應消息,不能被共享緩存處理。這允許服務器僅僅描述當前用戶的部分響應消息,此響應消息對于其他用戶的請求無效。 no-cache指示請求或響應消息不能緩存,該選項并不是說可以設置”不緩存“,而是需要和服務器確認 no-store在請求消息中發送將使得請求和響應消息都不使用緩存,完全不存下來。 max-age指示客戶機可以接收生存期不大于指定時間(以秒為單位)的響應。上次緩存時間(客戶端的)+max-age(64200s)<客戶端當前時間 min-fresh指示客戶機可以接收響應時間小于當前時間加上指定時間的響應。 max-stale指示客戶機可以接收超出超時期間的響應消息。如果指定max-stale消息的值,那么客戶機可以接收超出超時期指定值之內的響應消息。注意:這兩個header[Cache-Control、Expires]可以只啟用一個,也可以同時啟用,當response header中,Expires和Cache-Control同時存在時且時間不一致時,Cache-Control優先級高于Expires;
Last-Modified/If-Modified-Since
If-Modified-Since,和 Last-Modified 一樣都是用于記錄頁面最后修改時間的 HTTP 頭信息,只是 Last-Modified 是由服務器往客戶端發送的 HTTP 頭,而 If-Modified-Since 則是由客戶端往服務器發送的頭,
在瀏覽器第一次請求某一個URL時,服務器端的返回狀態會是200,內容是你請求的資源,同時有一個Last-Modified的屬性標記此文件在服務期端最后被修改的時間,格式類似這樣:
Last-Modified: Fri, 12 May 2006 18:53:33 GMT
客戶端第二次請求此URL時,根據 HTTP 協議的規定,瀏覽器會向服務器傳送 If-Modified-Since 報頭,詢問該時間之后文件是否有被修改過:
If-Modified-Since: Fri, 12 May 2006 18:53:33 GMT
如果服務器端的資源沒有變化,則自動返回 HTTP 304 (Not Changed.)狀態碼,內容為空,這樣就節省了傳輸數據量。當服務器端代碼發生改變或者重啟服務器時,則重新發出資源,返回和第一次請求時類似。從而保證不向客戶端重復發出資源,也保證當服務器有變化時,客戶端能夠得到最新的資源。
當與 If-None-Match 一同出現時,它會被忽略掉,除非服務器不支持 If-None-Match。
Etag/If-None-Match
ETag是響應頭,If-None-Match是請求頭。Last-Modified / If-Modified-Since的主要缺點就是它只能精確到秒的級別,一旦在一秒的時間里出現了多次修改,那么Last-Modified / If-Modified-Since是無法體現的。相比較,ETag / If-None-Match沒有使用時間作為判斷標準,而是使用一個特征串。Etag把Web組件的特征串告訴客戶端,客戶端在下次請求此Web組件的時候,會把上次服務端響應的特征串作為If-None-Match的值發送給服務端,服務端可以通過這個值來判斷是否需要從重新發送,如果不需要,就簡單的發送一個304狀態碼,客戶端將從緩存里直接讀取所需的Web組件。
HTTP 協議規格說明定義ETag為“被請求變量的實體值” (參見 ------ 章節 14.19)。 另一種說法是,ETag是一個可以與Web資源關聯的記號(token)。典型的Web資源可以一個Web頁,但也可能是JSON或XML文檔。服務器單獨負責判斷記號是什么及其含義,并在HTTP響應頭中將其傳送到客戶端,以下是服務器端返回的格式:
ETag: "50b1c1d4f775c61:df3"
客戶端的查詢更新格式是這樣的:
If-None-Match: W/"50b1c1d4f775c61:df3"
如果ETag沒改變,則返回狀態304然后不返回,這也和Last-Modified一樣。本人測試Etag主要在斷點下載時比較有用。
建議
當使用Expires / Cache-Control的時候,盡量給圖片,樣式表,腳本等設置一個足夠大的緩存時間,如果在此期間,緩存文件有過修改,最簡單的更新方式是改名或者 設置一個查詢參數,比如開始圖片名是logo.gif,如果做了一個新的圖片,你想更新,可以把圖片改名為logo_v2.gif,或者給圖片設置一個查 詢參數logo.gif?foobar,這樣,瀏覽器就會去請求新的圖片了。不過,并不是所有的Web組件都適合有一個大的緩存時間,比如html,就不 適合使用過大的緩存時間,否則你在緩存到期前,就沒機會更新任何東西了。
使用Yslow的都知道,它不建議使用ETag,理由是Etag在分布式環境里,會給服務器造成不必要的壓力,比如說在Apache里,Etag缺省是由 三個因素決定的:INode Size MTime,而同一個圖片,在不同服務器上的INode是不同的,所以在兩個服務器上先后請求同一個圖片,會得到兩次200,雖然我們可以通過設置 FileETag Size MTime來屏蔽INode,從而達到一次200,一次304的效果,但304也是要通過一次條件GET請求驗證的,所以說,還是通過Expires / Cache-Control來設置一個足夠大的緩存時間更劃算一些,如此說來,對圖片,樣式表,腳本等靜態內容而言,設置一個大的過期時間是絕對必要的, 而Etag和Last-Modified則不是必要的。
參考:https://segmentfault.com/a/11...
http://www.cnblogs.com/wrmfw/...
https://developer.mozilla.org...
總結
- 上一篇: Spring Boot使用maven打包
- 下一篇: UILabel 调整行间距