http缓存

2019-10-29  本文已影响0人  成熟稳重的李先生

http缓存分为两种, 强制缓存(网站首页不能做缓存)和对比缓存。

// cache.js
let http = require("http")
let mimie = require("mime"); //第三方模块,用于添加content-type
let url = require("url");
let path = require("path");
let fs = require("fs");
/ *
  * 首页的html文件可以使用对比缓存
  * 第一次访问的时候,设置一个头, “last-modified”--最后的修改时间
  * 下次在请求的时候,带上这个时间,看是否一致
  */
http
  .createServer((req, res) => {
    let { pathname } = url.parse(req.url, true);
    let absPath = path.join(__dirname, pathname);
    // js,css文件之类的, 每次更改了,就要重新请求,-----这是对比缓存

 /*
  * 强制缓存(如果服务器上文件修改了,但是每到缓存失效的时间,
  * 那么浏览器端不会更新,因此强制缓存是有局限性的)
  * 这种缓存只针对像js,css,img这类的文件
  */
   res.setHeader("Cache-Control", "max-age=5"); //相对时间,单位是秒
   res.setHeader("Expires", new Date(Date.now() + 5000).toUTCString());  // 绝对时间

    fs.stat(absPath, (err, statObj) => {
      if (err) {
        res.statusCode = 404;
        res.end(`Not Found`);
      }
      if (statObj.isFile()) {
         let ctime = statObj.ctime.toUTCString();
     /*
      * 对比缓存分两种:
      * 1). last-modified(最后修改时间)
     */
      /*
       * if-modified-since是浏览器自己携带的,
       * 如果服务器设置过last-modified,那么下次请求就会带上“if-modified-since
       * 缺陷:1)如果文件没变,但是时间改了
       *  2) 时间精确到秒,可能会有问题
       */

        if (req.headers["if-modified-since"] == ctime) {  // 如果时间没变,设置304
           res.statusCode = 304;
           res.end();
           return;
         }
        res.setHeader("Last-Modified", ctime);  //最后修改时间
   /*
    * 2). Etag(摘要)
    * Etag的方式比较靠谱,但是不能对大文件进行摘要文件Etag,可以采用“文件大小+文件的最后修改时间”来组成Etag
    */
        let md5 = crypto.createHash("md5");
        let rs = fs.createReadStream(absPath);
        let arr = []; //要先写入响应头,再写入响应体
        rs.on("data", function(data) {
          md5.update(data);
          arr.push(data);
        });
        rs.on("end", () => {
          let etag = md5.digest("base64");
        // "if-none-match"和"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));
        });

        res.setHeader("Content-Type", mime.getType(absPath) + ";charset=utf-8");
        fs.createReadStream(absPath).pipe(res);
      }
// 一般情况下,这两种缓存都使用,访问服务器时,会先加一个强制缓存,强制缓存n秒
// n秒过后,会在发送请求时使用对比缓存,先判断last-modified和if-modified-since,Etag和if-none-match,
// 如果都成立,则返回304,再强制缓存n秒
// 如果有变化,返回新的文件
// 304 = last-modified + if-modified-since  和 Etag + if-none-match(强制缓存不属于304)
    });
  })
  .listen(3000);
上一篇下一篇

猜你喜欢

热点阅读