web緩存及其實現,附簡單實現源碼

概述

http緩存的實現方式有html

1.Cache-Control/Expires。Cache-Control的Max-age屬性設置的絕對過時時間,單位爲秒。好比max-age:300,表示文件會緩存在本地300s以後過時.Expires表明的是絕對緩存時間,表示緩存在指定的時間點過時,格式爲Expires:Thu,20 Apr 2019 20:00:00 GMT。這個時間是由服務器設置的,但本地瀏覽器和服務器之間可能存在時差,因此有時這個值不許確。當Cache-Control的max-age和expires同時存在時,max-age的優先級高。node

2.Last-Modify/If-Modify-Since。這兩個是成對存在的,表明文件最後的修改時間, Last-Modified 是由服務器往瀏覽器發送的 HTTP頭,每次發送的值會寫進瀏覽器的If-Modify-Since中。If-Modified-Since是由瀏覽器往服務器發送的頭,瀏覽器每次請求服務器都會帶上這個頭。git

3.Etag/If-None-Match.這也是成對存在,功能和(2)相似。不過在開發中每每是對服務器的文件求Hash,並把求出的hash值賦給Etag。當Etag和Last-Modify同時存在的時候服務端對兩種都要校驗。github

4.Etag和Last-Modify對比。
(a)、服務器週期性動態生成的文件,他的內容並不改變,但修改時間變了這時咱們應該用Etag (b)、對於修改很是頻繁的文件,Etag能夠檢測到秒級如下,If-Modified-Since只能能檢查到s級的。瀏覽器

5.Last-Modified,Etag,Expire 混合使用
(a)、一般 Last-Modified,Etag,Expire 是一塊兒混合使用的,特別是 Last-Modified 和 Expire 常常一塊兒使用,由於 Expire 可讓瀏覽器徹底不發起 Http 請求,而當瀏覽器強制 F5 的時候又有 Last-Modified ,這樣就很好的達到了瀏覽器段緩存的效果。
(b)、Etag 和 Expire 一塊兒使用時,先判斷 Expire ,若是已通過期,再發起 Http 請求,若是 Etag 也過時,則返回 200 響應。若是 Etag 沒有過時則返回 304 響應。
(c)、Last-Modified,Etag,Expires 三個同時使用時。先判斷 Expire ,而後發送 Http 請求,服務器先判斷 last-modified ,再判斷 Etag ,必須都沒有過時,才能返回 304 響應緩存

實現

上面說了那麼一大堆,如今用node來實現一個Last-Modify/If-Modify-Since的緩存bash

1、實現一個簡單服務器

const http = require('http');
const fs = require('fs');
const urlLib = require('url');

http.createServer((req, res) => {
 let { pathname } = urlLib.parse(req.url, true);
 if (pathname != '/index.html') {
    res.writeHead(302, { 'Location': 'http://localhost:9090/index.html' });
        res.end();
 } else {
  let rs = fs.createReadStream(`./${pathname}`);
  rs.pipe(res);
 }

}).listen(9090);
console.log('server start at http://localhost:9090/index.html')
複製代碼

能夠看到不管怎麼刷新返回的Status都是200,而且響應頭中也沒有If-Modify-Since這項

2、讀取文件的修改時間並設置服務端Last-Modified

http.createServer((req, res) => {
    let { pathname } = urlLib.parse(req.url, true);
    if (pathname != '/index.html') {
        res.writeHead(302, { 'Location': 'http://localhost:9090/index.html' });
        res.end();
     } else {
  +     fs.stat(`./${pathname}`, (err, stat) => {
            if (err) {
                console.log('請在根目錄下建立一個index.html文件');
            } else {
   +              if (req.headers['if-modified-since']) {
   +                 console.log(req.headers['if-modified-since'])
                } 
   +             res.setHeader('Last-Modified', stat.mtime.toGMTString());
                let rs = fs.createReadStream(`./${pathname}`);
                rs.pipe(res);
               
                }
           })
  }
}).listen(9090);
複製代碼

如今咱們能夠看到瀏覽器的請求頭多了一個If-Modified-Since,且服務器能夠獲取到該值

3、用If-Modified-Since的值判斷服務器文件是否過時

fs.stat(`./${pathname}`, (err, stat) => {
            if (err) {
                console.log('請在根目錄下建立一個index.html文件');
            } else {
                if (req.headers['if-modified-since']) {
              +     let date = new Date(req.headers['if-modified-since']);
              +     let client_time = Math.floor(date.getTime() / 1000);
              +     let server_time = Math.floor(stat.mtime.getTime() / 1000);
              +      if (client_time < server_time) {
              +         sentFileToClient();
              +     } else {
              +         res.writeHead(304);
              +         res.write('Not Modified');
              +         res.end();
                    }
                } else {
                    sentFileToClient();
                }

                function sentFileToClient() {
                    res.setHeader('Last-Modified', stat.mtime.toGMTString());
                    let rs = fs.createReadStream(`./${pathname}`);
                    rs.pipe(res);
                }

            }

        })
複製代碼

咱們能夠看到第一次請求status是200,而後刷新都是304更改文件後status又變成了200
代碼地址: github.com/fanxuewen/e…
相關文章
相關標籤/搜索