1. 缓存作用 #

2. 请求流程 #

3. 通过最后修改时间来判断缓存是否可用 #

  1. Last-Modified:响应时告诉客户端此资源的最后修改时间
  2. If-Modified-Since:当资源过期时(使用Cache-Control标识的max-age),发现资源具有Last-Modified声明,则再次向服务器请求时带上头If-Modified-Since
  3. 服务器收到请求后发现有头If-Modified-Since则与被请求资源的最后修改时间进行比对。若最后修改时间较新,说明资源又被改动过,则响应最新的资源内容并返回200状态码;
  4. 若最后修改时间和If-Modified-Since一样,说明资源没有修改,则响应304表示未更新,告知浏览器继续使用所保存的缓存文件。
var matchHandle =  function(filename,req,res){
   //最后修改时间
    var ifModifiedSince  = new Date(req.headers['if-modified-since']);
    fs.stat(filename,function(err,stat){
        ////上次修改时间, 只发header
        if(ifModifiedSince == stat.mtime.toUTCString()){
            res.statusCode = 304;
            res.end('');
        }else{//如果时间不等则返回最新内容和最后修改时间
            res.setHeader('Last-Modified',stat.mtime.toGMTString());
            res.writeHead(200,'OK');
            fs.createReadStream(filename).pipe(res);
        }
    });
}

4. 最后修改时间存在问题 #

  1. 某些服务器不能精确得到文件的最后修改时间, 这样就无法通过最后修改时间来判断文件是否更新了。
  2. 某些文件的修改非常频繁,在秒以下的时间内进行修改. Last-Modified只能精确到秒
  3. 一些文件的最后修改时间改变了,但是内容并未改变。 我们不希望客户端认为这个文件修改了。
  4. 如果同样的一个文件位于多个CDN服务器上的时候内容虽然一样,修改时间不一样。

5. ETag #

ETag是实体标签的缩写,根据实体内容生成的一段hash字符串,可以标识资源的状态。当资源发生改变时,ETag也随之发生变化。 ETag是Web服务端产生的,然后发给浏览器客户端。

  1. 客户端想判断缓存是否可用可以先获取缓存中文档的ETag,然后通过If-None-Match发送请求给Web服务器询问此缓存是否可用。
  2. 服务器收到请求,将服务器的中此文件的ETag,跟请求头中的If-None-Match相比较,如果值是一样的,说明缓存还是最新的,Web服务器将发送304 Not Modified响应码给客户端表示缓存未修改过,可以使用。
  3. 如果不一样则Web服务器将发送该文档的最新版本给浏览器客户端
var eTagHandle = function(filename,req,res){
    fs.readFile(filename,function(err,content){
        var hash = getHash(content);
        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(content);
        }
    })
}

6. 如何干脆不发请求 #

浏览器会将文件缓存到Cache目录,第二次请求时浏览器会先检查Cache目录下是否含有该文件,如果有,并且还没到Expires设置的时间,即文件还没有过期,那么此时浏览器将直接从Cache目录中读取文件,而不再发送请求

7. 资源 #

本节视频