緩存是一種保存資源副本並在下次請求時直接使用該副本的技術。(MDN)javascript
這裏的web瀏覽器緩存主要指http緩存。css
內存緩存具備兩個特色,分別是快速讀取和時效性:快速讀取:內存緩存會將編譯解析後的文件,直接存入該進程的內存中,佔據該進程必定的內存資源,以方便下次運行使用時的快速讀取。時效性:一旦該進程關閉,則該進程的內存則會清空。html
硬盤緩存則是直接將緩存寫入硬盤文件中,讀取緩存須要對該緩存存放的硬盤文件進行I/O操做,而後從新解析該緩存內容,讀取複雜,速度比內存緩存慢。java
以瀏覽器中顯示的說明爲列:web
瀏覽器請求一個資源時,會按照優先級(Service Worker -> Memory Cache -> Disk Cache -> Push Cache)依次查找緩存,若是命中則使用緩存,不然發起請求。算法
以未開通Service Worker的服務訪問爲例:http://baidu.com–> 200 –> 關閉頁面的標籤頁 –> 從新打開http://baidu.com –> 200(from disk cache) –> 刷新 –> 200(from memory cache)。編程
網關緩存、CDN、反向代理緩存、負載均衡器等部署在服務器上的緩存瀏覽器
以騰訊 CDN 爲例:請求頭中 X-Cache-Lookup:Hit From MemCache 表示命中 CDN 節點的內存;X-Cache-Lookup:Hit From Disktank 表示命中 CDN 節點的磁盤;X-Cache-Lookup:Hit From Upstream 表示沒有命中 CDN。緩存
關鍵步驟以下:服務器
制強制緩存的字段分別是請求頭中的Expires和,其中Cache-Control優先級比Expires高。
Expires是HTTP/1.0控制網頁緩存的響應頭字段,其值爲服務器返回該請求結果緩存的到期時間,即再次發起該請求時,若是客戶端的時間小於Expires的值時,直接使用緩存結果。
Expires是HTTP/1.0的字段,可是如今瀏覽器默認使用的是HTTP/1.1,那麼在HTTP/1.1中網頁緩存仍是否由Expires控制?
到了HTTP/1.1,Expire已經被Cache-Control替代,緣由在於Expires控制緩存的原理是使用客戶端的時間與服務端返回的時間作對比,那麼若是客戶端與服務端的時間由於某些緣由(例如時區不一樣;客戶端和服務端有一方的時間不許確)發生偏差,那麼強制緩存則會直接失效,這樣的話強制緩存的存在則毫無心義。
HTTP/1.1定義的 Cache-Control 頭用來區分對緩存機制的支持狀況, 請求頭和響應頭都支持這個屬性。經過它提供的不一樣的值來定義緩存策略。
Pragma 是HTTP/1.0標準中定義的一個header屬性,請求中包含Pragma的效果跟在頭信息中定義Cache-Control: no-cache相同,可是HTTP的響應頭沒有明肯定義這個屬性,因此它不能拿來徹底替代HTTP/1.1中定義的Cache-control頭。一般定義Pragma以向後兼容基於HTTP/1.0的客戶端。
協商緩存的標識也是在響應報文的HTTP頭中和請求結果一塊兒返回給瀏覽器的,控制協商緩存的字段分別有:Last-Modified / If-Modified-Since和Etag / If-None-Match,其中Etag / If-None-Match的優先級比Last-Modified / If-Modified-Since高。
屬於 http 1.0。當帶着 If-Modified-Since 頭訪問服務器請求資源時,服務器會檢查 Last-Modified,若是 Last-Modified 的時間早於或等於 If-Modified-Since 則會返回一個不帶主體的 304 響應,不然將從新返回資源。
Last-Modified只能精確到一秒,能夠做爲一種弱校驗器。
屬於 http 1.1。ETag 是一個響應首部字段,強校驗器,它是根據實體內容生成的一段 hash 字符串,標識資源的狀態,由服務端產生。If-None-Match 是一個條件式的請求首部。若是請求資源時在請求首部加上這個字段,值爲以前服務器端返回的資源上的 ETag,則當且僅當服務器上沒有任何資源的 ETag 屬性值與這個首部中列出的時候,服務器纔會返回帶有所請求資源實體的 200 響應,不然服務器會返回不帶實體的 304 響應。
Last-Modified 標註的最後修改只能精確到秒級,若是某些文件在 1 秒鐘之內,被修改屢次的話,它將不能準確標註文件的新鮮度;
某些文件也許會週期性的更改,可是他的內容並不改變(僅僅改變的修改時間),但 Last-Modified 卻改變了,致使文件無法使用緩存;
有可能存在服務器沒有準確獲取文件修改時間,或者與代理服務器時間不一致等情形。
ETag 優先級比 Last-Modified 高,同時存在時會以 ETag 爲準。
是一個HTTP響應頭部信息,它決定了對於將來的一個請求頭,應該用一個緩存的回覆(response)仍是向源服務器請求一個新的回覆。它被服務器用來代表在 content negotiation algorithm(內容協商算法)中選擇一個資源表明的時候應該使用哪些頭部信息(headers)。它表示某個響應因某個響應頭部而不一樣。
好比 Vary: Accept 的意思即爲,響應因請求資源格式頭部而不一樣,那麼經過相同 URI 訪問的資源就能夠根據這個頭上知道其內容格式不一樣。
同一個 URL 能夠提供多份不一樣的文檔,這就要求服務端和客戶端之間有一個選擇最合適版本的機制,這叫作內容協商。服務端根據客戶端發送的請求頭中某些字段自動發送最合適的版本。能夠用於這個機制的請求頭字段又分兩種:內容協商專用字段(Accept 字段)、其餘字段。
例如:Accept-Encoding 屬於內容協商專用字段,服務端只須要在響應頭中增長 Content-Encoding 字段,用來指明內容壓縮格式;或者不輸出 Content-Encoding 代表內容未通過壓縮。緩存服務器,針對不一樣的 Content-Encoding 緩存不一樣內容,再根據具體請求中的 Accept-Encoding 字段返回最合適的版本。增長 Vary: Accept-Encoding 響應頭,明確告知緩存服務器按照 Accept-Encoding 字段的內容,分別緩存不一樣的版本;
F5的做用和直接在URI輸入欄中輸入而後回車是不同的,F5會讓瀏覽器不管如何都發一個HTTP Request給Server,即便先前的響應中有Expires頭部。因此,當我在 網頁中按F5的時候,瀏覽器會發送一個HTTP Request給Server,可是包含這樣的Headers:
Cache-Control: max-age=0 If-Modified-Since: Fri, 15 Jul 2016 04:11:51 GMT
其中Cache-Control是Chrome強制加上的,而If-Modified-Since是由於獲取該資源的時候包含了Last-Modified頭部,瀏覽器會使用If-Modified-Since頭部信息從新發送該時間以確認資源是否須要從新發送。 實際上Server沒有修改這個index.css文件,因此返回了一個304(Not Modified),這樣的響應信息很小,所消耗的route-trip很少,網頁很快就刷新了。
上面的例子中沒有ETag,若是Response中包含ETag,F5引起的Http Request中也是會包含If-None-Match的。
以上描述的客戶端瀏覽器緩存是指存儲位置在客戶端瀏覽器, 可是對客戶端瀏覽器緩存的實際設置工做是在服務器上的資源中完成的. 雖然上面介紹了有關於客戶端瀏覽器緩存的屬性, 可是實際上對這些屬性的設置工做都須要在服務器的資源中作設置. 一般有兩種操做手段對瀏覽器緩存進行設置, 一個是經過指令聲明來設置, 另一個是經過編程方式來設置.
例子1
配置指令expires,能夠控制 HTTP 響應中的Expires和Cache-Controle的值,默認是 off
location ~ .*.(js|css)?$ { expires 1y; }
例2:
對全部後綴爲.html 的請求,返回頭 cache-control 使用 no-cache 指令
location ~ .*\.(html)$ { try_files $uri $uri/ =404; root /data/web/default; add_header Cache-Control no-cache; }
例3:
etag設置
http { etag off;
例4
配置last-modified(默認開啓)
這裏再也不詳細描述,不一樣語言做出的server服務可查看相關模塊說明
以koa實現爲例:
//koastart var koa = require('koa'); var app = new koa(); // response app.use(function *(){ this.body = 'Hello World'; var etag = this.get('ETag'); console.log("etag:"+etag); var date = new Date; var hashStr = this.body; var hash = require("crypto").createHash('sha1').update(hashStr).digest('base64'); this.set({ 'Cache-Control':'max-age=120', 'Etag': hash, 'Last-Modified': new Date }); }); app.listen(3000);
MDN-http緩存:https://developer.mozilla.org... ;
HTTP緩存控制:https://imweb.io/topic/5795dc... ;
https://web.dev/http-cache/ ;
https://mp.weixin.qq.com/s/d2... ;
https://www.jiqizhixin.com/ar... ;