浅解强缓存和协商缓存

本文全部代码皆采用express搭建的简单服务器css

web缓存描述 :

Web 缓存是能够自动保存常见文档副本的 HTTP 设备。当 Web 请求抵达缓存时, 若是本地有“已缓存的”副本,就能够从本地存储设备而不是原始服务器中提取这 个文档。(此结论来自http权威指南)html

缓存的优缺点:

优势:web

  • 缓存减小了冗余的数据传输,节省了你的网络费用。
  • 缓存缓解了网络瓶颈的问题。不须要更多的带宽就可以更快地加载页面。
  • 缓存下降了对原始服务器的要求。服务器能够更快地响应,避免过载的出现。
  • 缓存下降了距离时延,由于从较远的地方加载页面会更慢一些。

缺点:express

  • 缓存中的数据可能与服务器的数据不一致;
  • 消耗内存;
缓存验证概述:
缓存可分为强缓存和协商缓存。

1,浏览器进行资源请求时,会判断response headers是否命中强缓存,若是命中,直接从本地读取缓存,不会向服务器发送请求,
2,当强缓存没有命中时,会发送请求到服务端,判断协商缓存是否命中,若是命中,服务器将请求返回,不会返回资源,告诉浏览器从本地读取缓存。如何不命中,服务器直接返回资源
区别: 强缓存命中,不会请求服务器,直接请求缓存;协商缓存命中,会请求服务器,不会返回内容,而后读取缓存;

缓存的处理流程

from memory cache 和 from disk cache的区别

from memory cache:字面理解是从内存中,其实也是字面的含义,这个资源是直接从内存中拿到的,不会请求服务器通常已经加载过该资源且缓存在了内存当中,当关闭该页面时,此资源就被内存释放掉了,再次从新打开相同页面时不会出现from memory cache的状况浏览器

from disk cache:同上相似,此资源是从磁盘当中取出的,也是在已经在以前的某个时间加载过该资源,不会请求服务器可是此资源不会随着该页面的关闭而释放掉,由于是存在硬盘当中的,下次打开仍会from disk cache (来自:blog.csdn.net/garrettzxd/…缓存

如下是缓存实现的四种方式

强缓存

强缓存又分为Expires 和 Cache-Control

Expires,该值是一个GMT时间格式个字符串,浏览器进行第一次请求时,服务器会在返回头部加上Expires,下次请求,若是在这个时间以前则命中缓存,bash

app.get('/', (req, res) => {
    const cssContent = path.join(__dirname, './html/index.html');
    fs.readFile(cssContent, function(err, data) {
          res.setHeader("Expires", new Date(Date.now() + 2592000000).toUTCString());
        res.end(data);
    })
});

复制代码

Cache-Control ,该值是利用max-age判断缓存的生命周期,是以秒为单位,如何在生命周期时间内,则命中缓存服务器

app.get('/', (req, res) => {
    const cssContent = path.join(__dirname, './html/index.html');
    fs.readFile(cssContent, function(err, data) {
        res.setHeader("Cache-Control", "max-age=0");
        res.end(data);
    })
});

复制代码

命中缓存: 网络

协商缓存

协商缓存利用Last-Modified , If-Modified-Since 和 ETag , If-None-Match来实现
Last-Modified , If-Modified-Since

Last-Modified: 表示为为实体头部部分,response返回,表示为资源的最后更新时间
If-Modified-Since:经过比较两次的时间判断,资源在请求期间是否有修改,假如没有修改,则命中协商缓存,浏览器从缓存中读取资源,若是没有命中,资源有过修改,返回新的Last-Modified时间和服务器资源app

app.get('/', (req, res) => {
    const cssContent = path.join(__dirname, './html/index.html')
    fs.stat(cssContent, (err, start) => {
        if (req.headers['if-modified-since'] === start.mtime.toUTCString()) {
            res.writeHead(304, 'Not Modified');
            res.end();
        } else {
            fs.readFile(cssContent, function (err, data) {
                let lastModified = start.mtime.toUTCString();
                res.setHeader('Last-Modified', lastModified);
                res.writeHead(200, 'OK');
                res.end(data);
            })
        }
    })

});
复制代码
ETag , If-None-Match

有些状况下仅判断最后修改日期来验证资源是否有改动是不够的:
1,存在周期性重写某些资源,但资源实际包含的内容并没有变化;
2,被修改的信息并不重要,如注释等;
3,Last-Modified没法精确到毫秒,但有些资源更新频率有时会小于一秒。

ETag:为相应头部字段,表示资源内容的惟一标识,随服务器response返回;
If-None-Match: 服务器比较请求头中的If-None-Match和当前资源中的etag是否一致,来判断资源是否修改过,若是没有修改,则命中缓存,浏览器从缓存中读取资源,若是修改过,服务器会返回新的etag,并返回资源;

app.get('/home', (req, res) => {
    const cssContent = path.join(__dirname, './html/index.html')
    fs.stat(cssContent, (err, start) => {
        let etag = md5(cssContent);
        if (req.headers['if-none-match'] === etag) {
            res.writeHead(304, 'Not Modified');
            res.end();
        } else {
            fs.readFile(cssContent, function (err, data) {
                res.setHeader('Etag', etag);
                res.writeHead(200, 'OK');
                res.end(data);
            })
        }
    })
});
复制代码

不推荐使用 Expires 首部,它指定的是实际的过时日期而不是秒数。HTTP 设计者 后来认为,因为不少服务器的时钟都不一样步,或者不正确,因此最好仍是用剩余秒 数,而不是绝对时间来表示过时时间。

ETag解决了Last-Modified使用时可能出现的资源的时间戳变了但内容没变及若是再一秒钟之内资源变化但Last-Modified没变的问题,感受ETag更加稳妥。

补充:根据浏览器缓存策略,Expire和Cache-Control用回车、后退、F5刷新会跳过本地缓存,每次都会从服务器中获数据。

相关文章
相关标签/搜索