5分钟了解缓存的概念

目的: 搞懂缓存的概念

阅读时长: 5 分钟

缓存的处理方式一般有以下两种:

  • 强制缓存
  • 比较缓存
1. 先来说说强制缓存
let http = require('http');
let mime = require('mime');
let url = require('url');
let path = require('path');
let fs = require('fs');

http.createServer(function(req, res) {
  let { pathname } = url.parse(req.url, true);
  res.setHeader('Cache-Control', 'max-age=5');
  res.setHeader('Expires', new Date(Date.now() + 10000).toGMTString());

  let abs = path.join(__dirname, pathname);
  fs.stat(path.join(__dirname, pathname), (err, stat) => {
    if(err) {
      res.sstatusCode = 404;
      res.end('NotFound');
      return;
    }
    if(stat.isFile()) {
      fs.createReadStream(abs).pipe(res);
    }
  })
}).listen(8080);
复制代码

上面的代码主要是用nodejs开启了一个服务,然后设置响应头

  res.setHeader('Cache-Control', 'max-age=10000');
  res.setHeader('Expires', new Date(Date.now() + 10000).toGMTString());
复制代码

能看到在响应头里面设置的值。

这样的话,5s内再请求这个资源,就会从缓存中取。

这种方式有明显的缺陷,因为如果5s之内如果文件改变了呢?

2. 比较缓存之last-modify

下面对之前的代码进行修改


let http = require('http');
let mime = require('mime');
let url = require('url');
let path = require('path');
let fs = require('fs');

http.createServer(function(req, res) {
  let { pathname } = url.parse(req.url, true);
  /**
  * @注意: 强制缓存部分代码注释掉
  */
  
  // res.setHeader('Cache-Control', 'max-age=5');
  // res.setHeader('Expires', new Date(Date.now() + 5000).toGMTString());

  let abs = path.join(__dirname, pathname);
  fs.stat(path.join(__dirname, pathname), (err, stat) => {
    if(err) {
      res.statusCode = 404;
      res.end('NotFound');
      return;
    }
    if(stat.isFile()) {
    /**
    * @ 注意: 以下代码为新增代码,获取当前时间,并设置响应头Last-modified
    * 如果下次请求的is-modified-since 和 当前的ctime相同
    * 说明在此期间,文件没有被修改过
    */
      let ctime = stat.ctime.toUTCString()
      res.setHeader('Last-Modified', ctime);
      if(req.headers['if-modified-since'] == ctime) {
        console.log(1)
        res.statusCode = 304;
        res.end();
        return;
      }

      fs.createReadStream(abs).pipe(res);
    }
  })
}).listen(8081);
复制代码

这样的话,只要资源没有改变,就始终从缓存中取。

这种方式同样有缺陷,last-modified只能精确到秒,如果在1s中多次改变数据呢?

继续看文件内容比较方法处理缓存e-tag
let http = require('http');
let mime = require('mime');
let url = require('url');
let path = require('path');
let fs = require('fs');
let crypto = require('crypto');

http.createServer(function(req, res) {
  let { pathname } = url.parse(req.url, true);

  let abs = path.join(__dirname, pathname);
  fs.stat(path.join(__dirname, pathname), (err, stat) => {
    if(err) {
      res.statusCode = 404;
      res.end('NotFound');
      return;
    }
    if(stat.isFile()) {
    
      let md5 = crypto.createHash('md5');
      let rs = fs.createReadStream(abs);
      let arr = [];
      rs.on('data', function(data) {
        md5.update(data);
        arr.push(data);
      })
      rs.on('end', function() {
        let etag = md5.digest('base64');
        res.setHeader('Etag', etag);
        res.end(Buffer.concat(arr));
      })
    }
  })
}).listen(8081);
复制代码

我们来看看原理是什么?

if(stat.isFile()) {
      // 通过crypto创建一个md5
      let md5 = crypto.createHash('md5');
      let rs = fs.createReadStream(abs);
      let arr = [];
      rs.on('data', function(data) {
        // 读取数据的时候,用md5更新
        md5.update(data);
        arr.push(data);
      })
      rs.on('end', function() {
        let etag = md5.digest('base64');
        // 生成base-64,并设置响应头,Etag
        // 下次请求的时候,用etag和带过来的if-None-Match进行比较
        if(req.headers['if-none-match'] === etag) {
          res.statusCode = 304;
          res.end();
          return;
        }
        res.setHeader('Etag', etag);
        res.end(Buffer.concat(arr));
      })
    }

复制代码

下图会发现,文件请求statuscode为304

这种方式是非常安全的,但是,如果文件太大的话,每次都要读取文件内容就会很耗性能。


总结:

现在一般采用的方式是,用last-modified + etag。且e-tag不使用文件内容去生成base-64,而是使用文件的大小生成base-64

这里就不再赘述。

感谢阅读!

我是海明月,前端小学生。

转载于:https://juejin.im/post/5cc40581e51d456e31164a56

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值