Node.js实现浏览器缓存

 

 

        图 1 使用缓存的流程示意图浏览器

下面从三个规则分别来说:缓存

  1. 添加Expires或Cache-Control到报文头中;
  2. 配置Etags;
  3. 让Ajax缓存。
  • 条件请求

请求头部设置了If-Modified-Since,浏览器向服务器请求资源,服务端返回304状态码,浏览器则会使用本地文件。服务器

var handle = function (req, res) {
    fs.stat(filename, function (err, stat) {
        var lastModified = stat.mtime.toUTCString();
        if (lastModified === req.headers['if-modified-since']) {
            res.writeHead(304, "Not Modified");
            res.end();
        } else {
            fs.readFile(filename, function(err, file) {
                var lastModified = stat.mtime.toUTCString();
                res.setHeader("Last-Modified", lastModified);
                res.writeHead(200, "Ok");
                res.end(file);
            });
        }
    });
};

这里采用时间戳的方式来实现,时间戳的方式有一些缺陷:spa

文件的时间戳改动了但内容不必定改动。code

时间戳只能精确到秒级别,更新频繁的内容将没法生效。blog

Etags(Entity Tag)能够解决这个问题,由服务端生成,生成规则随意。通常是根据文件内容生成散列值,那么条件请求将不会受到时间戳改动形成带宽的浪费。与If-Modified-Since/Last-Modified不一样的是,Etags的请求相应是:If-None-Match/ETag资源

var getHash = function (str) {
    var shasum = crypto.createHash('sha1'); return shasum.update(str).digest('base64'); }; var handle = function (req, res) { fs.readFile(filename, function(err, file) { var hash = getHash(file); var noneMatch = req.headers['if-none-match']; if (hash === noneMatch) { res.writeHead(304, "Not Modified"); res.end(); } else { res.setHeader("ETag", hash); res.writeHead(200, "Ok"); res.end(file); } }); };

尽管条件请求能够在文件内容没有改变的状况下节省带宽,可是仍是须要请求服务器,那么能够不请求服务器直接取本地文件吗?字符串

  • 非条件请求(在服务端响应内容时,让浏览器明确地将内容缓存起来)

Expires是一个GMT格式的时间字符串(GMT时间与北京时间相互能够转化),在服务器端设置Expires能够告知浏览器要缓存的内容,只要本地还存在这个文件,在过时时间以前,都不会再发起请求。get

var handle = function (req, res) {
    fs.readFile(filename, function(err, file) {
        var expires = new Date();
        expires.setTime(expires.getTime() + 10 * 365 * 24 * 60 * 60 * 1000);
        res.setHeader("Expires", expires.toUTCString());
        res.writeHead(200, "Ok");
        res.end(file);
    });
};

*缺陷:若是用户本地时间和服务器时间不一致,那么这个缓存机制就存在问题。hash

Cache-Control能够避免这个问题,Cache-Control设置了一个max-age值,表示通过多长时间以后过时。(Cache-Control的优先级高于Expires

var handle = function (req, res) {
    fs.readFile(filename, function(err, file) {
        res.setHeader("Cache-Control", "max-age=" + 10 * 365 * 24 * 60 * 60 * 1000);
        res.writeHead(200, "Ok");
        res.end(file);
    });
};
  • 清除缓存

咱们设置缓存能够节省带宽,可是也会带来新的问题,若是文件内容发生变化,怎么通知用户去更新呢?

  1. 日期时间版本号:http://example.com?v=20170223
  2. 文件内容hash值: http://example.com?v=bahbdhjsdjs
相关文章
相关标签/搜索