要:添加Expires頭能有效的利用瀏覽器的緩存能力來改善頁面的性能,能在後續的頁面中有效避免不少沒必要要的Http請求,WEB服務器使用Expires頭來告訴Web客戶端它可使用一個組件的當前副本,直到指定的時間爲止。javascript
例如:Expires:Thu,15 Apr 2010 20:00:00 GMT; 他告訴瀏覽器緩存有效性持續到2010年4月15日爲止,在這個時間以內相同的請求使用緩存,這個時間以外使用http請求。html
Cathe-Control:max-age=315360000java
Expires有一個很是大的缺陷,它使用一個固定的時間,要求服務器與客戶端的時鐘保持嚴格的同步,而且這一天到來後,服務器還得從新設定新的時間。node
HTTP1.1引入了Cathe-Control,它使用max-age指定組件被緩存多久,從請求開始在max-age時間內瀏覽器使用緩存,以外的使用請求,這樣就能夠消除Expires的限制,瀏覽器
若是對瀏覽器兼容性要求很高的話,能夠兩個都使用。緩存
這裏對http 304 狀態結合max-age作一個總結:服務器
瀏覽器初次訪問服務器---------------服務器返回200狀態工具
以下圖:性能
瀏覽器再次請求服務器時,瀏覽器會先判斷max-age,若是到期則直接請求服務器,不然直接從緩存中取,ui
服務器收到請求後,判斷文件是否被修改過,如果則直接返回200,不然返回304,瀏覽器將從緩存中獲取文件。
若同步刷新頁面,則瀏覽器並不會先判斷max-age,而是直接發送請求,服務器接收到請求後,判斷文件是否有變化,如有則返回200,若沒有則返回304
修訂文件名
瀏覽器利用max-age取出緩存有很大的缺陷,若是在max-age時間內,服務器文件有修改,這樣用戶就不能第一時間獲取最新的信息,所以這裏最有效的方法是修改請求的文件名。
但爲了確保用戶能獲取組件最新版本,須要在整個項目中修改組件的文件名,這取決於你的html頁面,這項工做可能很輕鬆也可能很痛苦,
今天在羣裏聊天。說道了Expires。這裏來講明下這兩個的區別吧。
1.概念
Cache-control 用於控制HTTP緩存(在HTTP/1.0中可能部分沒實現,僅僅實現了 Pragma: no-cache)
Expires 表示存在時間,容許客戶端在這個時間以前不去檢查(發請求),等同max-age的效果。可是若是同時存在,則被Cache-Control的max-age覆蓋。
Cache-Control 的含義
可緩存性
public,http 請求返回的過程中,在 cache-control 中設置這個值,表明 http 請求返回的內容所通過的任何路徑當中(包括中間一些http代理服務器以及發出請求的客戶端瀏覽器),均可以對返回內容進行緩存操做。
private,表明只有發起請求的瀏覽器才能夠進行緩存
no-cache,能夠在本地進行緩存,但每次發請求時,都要向服務器進行驗證,若是服務器容許,才能使用本地緩存。
到期
max-age=,緩存多少秒後過時,過時以後瀏覽器纔會再次發送請求。
s-maxage=,瀏覽器基本用不到,會代替 max-age,但只有在代理服務器中才會生效。在代理服務器中,若是都設置了 max-age,s-maxage,仍是會讀取 s-maxage。
max-stale=,瀏覽器基本用不到,當 max-age 過時後,若是返回資源中有 max-stale 的設置。max-stale 是發起請求方主動攜帶的頭,即便 max-age 過時,只要 max-stale 沒過時,能夠繼續使用緩存資源,不須要從新請求。瀏覽器主動設置這個頭,只有在發起端纔有用。
從新驗證
must-revalidate,瀏覽器可能會用到,若是 max-age 過時,須要從新發送請求,獲取這部分數據,再來驗證數據是否真的過時,而不能直接使用本地緩存。
proxy-revalidate,用在緩存服務器中,指定緩存服務器過時後,必須向源服務器從新請求,不能直接使用本地緩存。
其餘
no-store,本地和代理服務器都不能夠存儲緩存,每次都要從新請求,拿到內容。
no-transform,主要是用在 proxy 服務器,不容許進行格式轉換。
Cache-Control 的使用
瀏覽器緩存
經過 Cache-Control 以及 max-age 設置,達到長緩存的效果。
啓動服務器 node server.js,在 localhost:8888 打開,查看network,當設置 max-age 後,刷新頁面,瀏覽器直接從緩存中進行讀取,不去要再向服務器請求,達到緩存靜態資源的目的。
存在的問題,服務端修改返回內容,客戶端沒有加載新的內容,由於請求 url 沒變,瀏覽器會直接從緩存讀取,不須要通過服務端驗證,致使靜態資源更新後,沒有及時更新到客戶端。
解決方案,打包靜態資源時,根據內容進行 hash 計算,生成文件名的 hash 碼。內容變,hash 碼變,請求資源 url 變,瀏覽器從新請求加載資源,達到更新緩存的目的。
// server.js const http = require('http') const fs = require('fs') http.createServer(function (request, response) { console.log('request come', request.url) if (request.url === '/') { const html = fs.readFileSync('test.html', 'utf8') response.writeHead(200, { 'Content-Type': 'text/html' }) response.end(html) } if (request.url === '/script.js') { response.writeHead(200, { 'Content-Type': 'text/javascript', 'Cache-Control': 'max-age=200' // 瀏覽器緩存時間 }) response.end('console.log("script loaded twice")') } }).listen(8888) console.log('server listening on 8888')
max-age能夠接收不少值,如 ‘Cache-Control’: ‘max-age=200, public’
緩存驗證Last-Modified和Etag的使用
資源驗證
驗證頭
Last-Modified
Etag
Last-Modified
上次修改時間。
配合If-Modified-Since或If-Unmodified-Since使用,一般瀏覽器使用前者。
服務器對比上次修改時間以驗證資源是否須要更新。
Etag
數據簽名,資源內容會對應有一個惟一的簽名,若是資源數據更改,簽名也會變。
配合If-Match或者If-None-Match使用,其值就是服務端返回的 Etag 值
對比資源的簽名判斷是否使用緩存
驗證頭的使用
服務器設置 Last-Modifed 和 Etag 的值,瀏覽器請求會攜帶這兩個頭,在請求頭中,會有 If-Modified-since: Last-Modifed值 和 If-None-Match: Etag值。
這時 response 中是有內容的,這裏但願服務器不返回實際的內容,只須要告訴瀏覽器直接讀取緩存便可。經過在服務器端進行判斷。
這時查看 respones 發現仍是有內容,這個內容是 Chrome 瀏覽器 從緩存中讀取顯示出來的,服務器沒有返回內容。
如何判斷服務端經過驗證,可是從緩存讀取的呢,經過服務器設置 HTTP Code 304,Not Modified 表示資源沒有修改,直接讀緩存,這時就會忽略服務端返回的內容。
Chrome 瀏覽器 控制檯 勾上 Disable cache,刷新頁面,發送的請求中就不包括和緩存相關的頭了
// server.js const http = require('http') const fs = require('fs') http.createServer(function (request, response) { console.log('request come', request.url) if (request.url === '/') { const html = fs.readFileSync('test.html', 'utf8') response.writeHead(200, { 'Content-Type': 'text/html' }) response.end(html) } if (request.url === '/script.js') { console.log(request.headers) const etag = request.headers['if-none-match'] if(etag === '777') { response.writeHead(304, { 'Content-Type': 'text/javascript', 'Cache-Control': 'max-age=2000000, no-cache', 'Last-Modified': '123', 'Etag': '777' }) response.end('') // 這裏不傳任何內容,即便有內容,瀏覽器也不會讀取 } else { response.writeHead(200, { 'Content-Type': 'text/javascript', 'Cache-Control': 'max-age=2000000, no-cache', // 經過 no-cache,即便沒過時瀏覽器也要向服務器驗證,不會從緩存讀取。 'Last-Modified': '123', // 隨便設的值 'Etag': '777' }) response.end('console.log("script loaded twice")') } } }).listen(8888) console.log('server listening on 8888')
no-cache
不從緩存讀取
'Cache-Control': 'max-age=2000000, no-cache', // 經過 no-cache,即便沒過時瀏覽器也要向服務器驗證,不會從緩存讀取。
no-store
設置 no-store,即便服務器下發了緩存相關頭,瀏覽器也會忽略任何和緩存相關的信息,發送請求不會攜帶相關頭,直接去請求最新的數據。
Chrome瀏覽器->右上角->更多工具->清理瀏覽器緩存
'Cache-Control': 'max-age=2000000, no-store'