前端性能優化 —— 添加Expires頭與Cache-control區別


要:添加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'


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM