要:添加Expires頭能有效的利用瀏覽器的緩存能力來改善頁面的性能,能在后續的頁面中有效避免很多不必要的Http請求,WEB服務器使用Expires頭來告訴Web客戶端它可以使用一個組件的當前副本,直到指定的時間為止。
例如:Expires:Thu,15 Apr 2010 20:00:00 GMT; 他告訴瀏覽器緩存有效性持續到2010年4月15日為止,在這個時間之內相同的請求使用緩存,這個時間之外使用http請求。
Cathe-Control:max-age=315360000
Expires有一個非常大的缺陷,它使用一個固定的時間,要求服務器與客戶端的時鍾保持嚴格的同步,並且這一天到來后,服務器還得重新設定新的時間。
HTTP1.1引入了Cathe-Control,它使用max-age指定組件被緩存多久,從請求開始在max-age時間內瀏覽器使用緩存,之外的使用請求,這樣就可以消除Expires的限制,
如果對瀏覽器兼容性要求很高的話,可以兩個都使用。
這里對http 304 狀態結合max-age做一個總結:
瀏覽器初次訪問服務器---------------服務器返回200狀態
如下圖:
瀏覽器再次請求服務器時,瀏覽器會先判斷max-age,如果到期則直接請求服務器,否則直接從緩存中取,
服務器收到請求后,判斷文件是否被修改過,若是則直接返回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的含義和使用
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'