在平時的前端開發中咱們常常會遇到這種操做。明明我代碼更新了,咋刷出來仍是之前的呢?是否是緩存了?快清下緩存看看!你看頁面是304,怪不得沒更新!等等不少狀況。做者起初也不是很瞭解,由於這個不禁前端來控制,都是後端的操做。故此次使用node也來寫一個控制緩存的服務來真正搞明白這裏的道道。歡迎關注個人博客,不按期更新中——javascript
在說這個服務如何寫以前咱們先要明白瀏覽器緩存究竟是個啥。來看下這個簡略示意圖:css
能夠看到瀏覽器的緩存機制分爲兩個部分。一、當前緩存是否過時?二、服務器中的文件是否有改動?前端
這是判斷是否啓用緩存的第一步。若是瀏覽器經過某些條件(條件以後再說)判斷出來,ok如今這個緩存沒有過時能夠用,那麼連請求都不會發的,直接是啓用以前瀏覽器緩存下來的那份文件:java
若是服務器發現這個文件改變了那麼你確定不能再用之前瀏覽器的緩存了,那就返回個200而且帶上新的文件:
node
同時若是發現雖然那個緩存雖然過時了,可你在服務器端的文件沒有變過,那麼服務器只會給你返回一個頭信息(304),讓你繼續用你那過時的緩存,這樣就節省了不少傳輸文件的時間帶寬啥的。看下圖:git
過時了的緩存須要請求一次服務器,若服務器判斷說這個文件沒有改變還能用,那就返回304。瀏覽器認識304,它就會去讀取過時緩存。不然就真的傳一份新文件到瀏覽器。github
在剛纔的敘述中做者沒有提到具體的判斷過時及變更的實現方式,這也是爲了可讓童鞋們現有一個總體的概念,無關乎代碼,至少經過上面一段講述,能夠認識到「哦瀏覽器的緩存是這樣一個流程」,就夠了。下面咱們來看下具體的如何操做:web
主要的方式有兩種,這兩種都是設定請求頭中的某一個字段來實現的:一、Expires;二、Cache-Control。因爲Cache-Control設置後優先級比前者高,此次做者就先說下經過Cache-Control來控制緩存。
後端
能夠看到Cache-Control字段有不少值,其餘的值有興趣的同窗能夠本身嘗試,如今做者要說最後一個值max-age;若是在請求頭中設定了瀏覽器
var maxAgeTime = 60 //過時時間
res.writeHead(200, {
"Cache-Control": 'max-age=' + maxAgeTime
})複製代碼
那麼在60s內,若是再去請求這個文件的話,是不會發起請求的。由於尚未過時呢!惟一例外是若是這個文件是你在瀏覽器地址欄輸入的地址來請求的(好比你請求localhost:3030/static/style.css),當你刷新的時候就會讓當前的這個文件所設定的過時時間失效,直接去請求服務器來看是返回個304仍是返回新文件。通常這麼請求的都是咱們常說的入口文件,入口文件一刷新就會從新向服務器請求,可是入口文件裏面所引入的文件如js,css等不會隨着刷新而另過時時間失效。除非你單找出來那個引入連接,經過瀏覽器地址欄去查詢它並刷新 :)。
經常使用的方式爲Etag和Last-Modified,思路上差很少,這裏做者只介紹Last-Modified的用法。
Last-Modified方式須要用到兩個字段:Last-Modified & if-modified-since。
先來看下這兩個字段的形式:
能夠看出其實形式是同樣的,就是一個標準時間。那麼怎麼用呢?來看下圖:
本次使用了Cache-Control&Last-Modified來作爲緩存機制的判斷條件。固然還有多種方式可使用,但願瞭解更全面的同窗能夠去讀讀這篇文章:Web瀏覽器的緩存機制
總結前兩個部分能夠得出如下的流程圖,如今再看這張圖應該仍是很明瞭的了。
var http = require("http")
var fs = require("fs")
var url = require("url")
http.createServer(function(req,res){
var pathname = url.parse(req.url).pathname
var fsPath = __dirname + pathname
fs.access(fsPath, fs.constants.R_OK, function(err){ //fs.constants.R_OK - path 文件可被調用進程讀取
if(err) {
console.log(err) //可返回404,在此簡略代碼再也不演示
}else {
var file = fs.statSync(fsPath) //文件信息
var lastModified = file.mtime.toUTCString()
var ifModifiedSince = req.headers['if-modified-since']
//傳回Last-Modified後,再請求服務器會攜帶if-modified-since值來和服務器中的Last-Modified比較
var maxAgeTime = 3 //設置超時時間
if(ifModifiedSince && lastModified == ifModifiedSince) { //客戶端修改時間和服務端修改時間對比
res.writeHead(304,"Not Modified")
res.end()
} else {
fs.readFile(fsPath, function(err,file){
if(err) {
console.log('readFileError:', err)
}else {
res.writeHead(200,{
"Cache-Control": 'max-age=' + maxAgeTime,
"Last-Modified" : lastModified
})
res.end(file)
}
})
}
}
})
}).listen(3030)複製代碼
代碼很簡單,看註釋便可。這只是一個微小的服務,咱們只是關注在文件緩存的方面。
慣例po做者的博客,不定時更新中——有問題歡迎在issues下交流,捂臉求star=。=