基於node的微小服務——細說緩存與304

寫在最前

在平時的前端開發中咱們常常會遇到這種操做。明明我代碼更新了,咋刷出來仍是之前的呢?是否是緩存了?快清下緩存看看!你看頁面是304,怪不得沒更新!等等不少狀況。做者起初也不是很瞭解,由於這個不禁前端來控制,都是後端的操做。故此次使用node也來寫一個控制緩存的服務來真正搞明白這裏的道道。歡迎關注個人博客,不按期更新中——javascript

瀏覽器緩存機制

在說這個服務如何寫以前咱們先要明白瀏覽器緩存究竟是個啥。來看下這個簡略示意圖:css

能夠看到瀏覽器的緩存機制分爲兩個部分。一、當前緩存是否過時?二、服務器中的文件是否有改動?前端

第一步:判斷當前緩存是否過時

這是判斷是否啓用緩存的第一步。若是瀏覽器經過某些條件(條件以後再說)判斷出來,ok如今這個緩存沒有過時能夠用,那麼連請求都不會發的,直接是啓用以前瀏覽器緩存下來的那份文件:java


圖中看到這個css文件緩存沒有過時,被瀏覽器直接經過緩存讀取了出來,注意 這個時候是不會向瀏覽器請求的! 若是過時了就會向服務器從新發起請求, 可是不必定就會從新拉取文件!

第二步:判斷服務器中的文件是否有改動

一、緩存過時,文件有改動

若是服務器發現這個文件改變了那麼你確定不能再用之前瀏覽器的緩存了,那就返回個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。
先來看下這兩個字段的形式:

  • Last-Modified : Fri , 12 May 2006 18:53:33 GMT
  • If-Modified-Since : Fri , 12 May 2006 18:53:33 GMT

能夠看出其實形式是同樣的,就是一個標準時間。那麼怎麼用呢?來看下圖:


當第一次請求某一個文件的時候,就會傳遞回來一個Last-Modified 字段,其內容是這個文件的修改時間。當這個文件緩存過時,瀏覽器又向服務器請求這個文件的時候,會自動帶一個請求頭字段If-Modified-Since,其值是上一次傳遞過來的Last-Modified的值,拿這個值去和服務器中如今這個文件的最後修改時間作對比,若是相等,那麼就不會從新拉取這個文件了,返回304讓瀏覽器讀過時緩存。若是不相等就從新拉取。

緩存機制流程

本次使用了Cache-Control&Last-Modified來作爲緩存機制的判斷條件。固然還有多種方式可使用,但願瞭解更全面的同窗能夠去讀讀這篇文章:Web瀏覽器的緩存機制

總結前兩個部分能夠得出如下的流程圖,如今再看這張圖應該仍是很明瞭的了。

node實現可緩存的服務

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=。=

相關文章
相關標籤/搜索