一、瀏覽器緩存
1,第一次請求,無緩存請求過程

流程如下所示
第二次請求,有緩存請求的過程

流程如下圖所示
瀏覽器的緩存分為二種,第一種的是強緩存,另外一種是協商緩存
2 :強緩存
定義:強緩存在請求資源的時候,會從header里面讀取是否是強緩存,在有效的時間時間期內,從緩存里讀取不能從服務那里讀取
介紹使用:
expires,這是http1.0時的規范;它的值為一個絕對時間的GMT格式的時間字符串,如Mon, 10 Jun 2015 21:31:12 GMT,如果發送請求的時間在expires之前,那么本地緩存始終有效,否則就會發送請求到服務器來獲取資源
cache-control:的含義和使用
可緩存性屬性說明
pubilc:http只要經過的地方都要進行緩存
privite:發出的瀏覽器端要進行緩存
no-cache:本地可以有緩存,需要服務器驗證才可以使用
no-store:本地和服務器都沒有緩存
max-age=<seconds> :緩存的最大的時間
3,代碼案例分析:
1,簡單的創建一個服務
const http = require('http');
const fs = require('fs');
// 創建一個http服務
http.createServer((request, response) => {
console.log('request-url' + 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') {
// const html = fs.readFileSync('test.html', 'utf8');
response.writeHead(200, {
'Content-Type': 'text/javascript',
'Cache-control': 'max-age=200 ',
})
response.end('ffff');
}
}).listen(8888);
4,解決的方法呢:
上面說到,使用強緩存時,瀏覽器不會發送請求到服務端,根據設置的緩存時間瀏覽器一直從緩存中獲取資源,在這期間若資源產生了變化,瀏覽器就在緩存期內就一直得不到最新的資源,那么如何防止這種事情發生呢?
通過更新頁面中引用的資源路徑,讓瀏覽器主動放棄緩存,加載新資源。
前端常常后面加上版本號和一些hash值重新的讀取
二、介紹協商緩存
協商緩存都是由服務器來確定緩存資源是否可用的,所以客戶端與服務器端要通過某種標識來進行通信,從而讓服務器判斷請求資源是否可以緩存訪問,這主要涉及到下面兩組header字段,這兩組搭檔都是成對出現的,即第一次請求的響應頭帶上某個字段(Last-Modified或者Etag),則后續請求則會帶上對應的請求字段(If-Modified-Since或者If-None-Match),若響應頭沒有Last-Modified或者Etag字段,則請求頭也不會有對應的字段。
Last-Modified/If-Modified-Since
二者的值都是GMT格式的時間字符串,具體過程:瀏覽器第一次跟服務器請求一個資源,服務器在返回這個資源的同時,在respone的header加上Last-Modified的header,這個header表示這個資源在服務器上的最后修改時間
瀏覽器再次跟服務器請求這個資源時,在request的header上加上If-Modified-Since的header,這個header的值就是上一次請求時返回的Last-Modified的值
服務器再次收到資源請求時,根據瀏覽器傳過來If-Modified-Since和資源在服務器上的最后修改時間判斷資源是否有變化,如果沒有變化則返回304 Not Modified,但是不會返回資源內容;如果有變化,就正常返回資源內容。當服務器返回304 Not Modified的響應時,response header中不會再添加Last-Modified的header,因為既然資源沒有變化,那么Last-Modified也就不會改變,這是服務器返回304時的response header
瀏覽器收到304的響應后,就會從緩存中加載資源
如果協商緩存沒有命中,瀏覽器直接從服務器加載資源時,Last-Modified的Header在重新加載的時候會被更新,下次請求時,If-Modified-Since會啟用上次返回的Last-Modified值
Etag/If-None-Match
這兩個值是由服務器生成的每個資源的唯一標識字符串,只要資源有變化就這個值就會改變;其判斷過程與Last-Modified/If-Modified-Since類似,與Last-Modified不一樣的是,當服務器返回304 Not Modified的響應時,由於ETag重新生成過,response header中還會把這個ETag返回,即使這個ETag跟之前的沒有變化。
3、既生Last-Modified何生Etag
你可能會覺得使用Last-Modified已經足以讓瀏覽器知道本地的緩存副本是否足夠新,為什么還需要Etag呢?HTTP1.1中Etag的出現主要是為了解決幾個Last-Modified比較難解決的問題:
一些文件也許會周期性的更改,但是他的內容並不改變(僅僅改變的修改時間),這個時候我們並不希望客戶端認為這個文件被修改了,而重新GET;
某些文件修改非常頻繁,比如在秒以下的時間內進行修改,(比方說1s內修改了N次),If-Modified-Since能檢查到的粒度是s級的,這種修改無法判斷(或者說UNIX記錄MTIME只能精確到秒);
某些服務器不能精確的得到文件的最后修改時間。
這時,利用Etag能夠更加准確的控制緩存,因為Etag是服務器自動生成或者由開發者生成的對應資源在服務器端的唯一標識符。
Last-Modified與ETag是可以一起使用的,服務器會優先驗證ETag,一致的情況下,才會繼續比對Last-Modified,最后才決定是否返回304。
4,代碼案例
if (etag === '777') {
response.writeHead(304, {
'Content-Type': 'text/javascript',
'Cache-control': 'max-age=200000,no-cache',
'last-Modified': '123',
'Etag': '777',
})
response.end('');
} else {
response.writeHead(200, {
'Content-Type': 'text/javascript',
'Cache-control': 'max-age=200000,no-cache',
'last-Modified': '123',
'Etag': '777',
})
response.end('fffff');
}
三、強緩存與協商緩存的區別,可以用下表來進行描述:
獲取資源形式 | 狀態碼 | 發送請求到服務器 | |
強緩存 | 從緩存取 | 200(from cache) | 否,直接從緩存取 |
協商緩存 | 從緩存取 | 304(not modified) | 是,正如其名,通過服務器來告知緩存是否可用 |