沒有緩存的世界,每次請求都是嚴格意義上的新的請求,那麼服務器端的壓力可想而知,客戶端的響應速度也是大打折扣,就是咱們在寫程序也知道須要緩存,把一些經常使用的數據緩存區來,避免每次都要從新讀取,特別是前端在進行元素獲取時,雖然鏈式調用讓咱們很舒服,可是若是每次都須要從新獲取這個元素的話,最好仍是使用變量緩存起來比較好。javascript
目前比較常見的緩存機制包括如下幾種[都是設置http header]:html
Expires前端
Cache-Controljava
Last-Modified/If-Modified-Since:Last-Modified/If-Modified-Since要配合Cache-Control使用。node
Etag/If-None-Match:Etag/If-None-Match也要配合Cache-Control使用
一個實際資源訪問的響應頭部部分信息以下:web
cache-control:max-age=691200 content-encoding:gzip content-type:application/javascript date:Sat, 05 Aug 2017 13:27:45 GMT etag:W/"59845e75-2cfb5" expires:Sat, 12 Aug 2017 11:47:47 GMT last-modified:Fri, 04 Aug 2017 11:45:57 GMT
Expires是http1.0提出的一個表示資源過時時間的header,它描述的是一個絕對時間,由服務器返回,用GMT格式的字符串表示,如:Expires:Thu, 31 Dec 2016 23:55:55 GMT,segmentfault
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描述的是一個相對時間,在進行緩存命中的時候,都是利用客戶端時間進行判斷,因此相比較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;
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.)狀態碼,內容爲空,這樣就節省了傳輸數據量。當服務器端代碼發生改變或者重啓服務器時,則從新發出資源,返回和第一次請求時相似。從而保證不向客戶端重複發出資源,也保證當服務器有變化時,客戶端可以獲得最新的資源。
注意:ast-Modified標註的最後修改只能精確到秒級,若是某些文件在1秒鐘之內,被修改屢次的話,它將不能準確標註文件的修改時間(沒法及時更新文件) 若是某些文件會被按期生成,當有時內容並無任何變化,但Last-Modified卻改變了,致使文件無法使用緩存,有可能存在服務器沒有準確獲取文件修改時間,或者與代理服務器時間不一致等情形(沒法使用緩存)。
當與 If-None-Match 一同出現時,它會被忽略掉,除非服務器不支持 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...