http缓存

693 阅读3分钟

直接上代码,代码胜过一切

main.js

/*
 * @Description: 缓存
 * @Author: shenah
 * @Date: 2020-03-24 16:06:35
 * @LastEditors: shenah
 * @LastEditTime: 2020-03-27 10:02:34
 */

// 创建服务器

const Koa = require("koa");
const cacheRouter = require("./cacheRouter");
const cors = require("koa2-cors");
const app = new Koa();
app.use(cors()).use(cacheRouter);
app.listen(8888);

cacheRouter.js

/*
 * @Description: 测试缓存策略
 * @Author: shenah
 * @Date: 2020-03-26 09:03:10
 * @LastEditors: shenah
 * @LastEditTime: 2020-03-27 11:22:01
 */

const Router = require("koa-router");
const Mock = require("mockjs");
const fs = require("fs");

const router = new Router();
const cacheRouter = new Router();

router.get("/cache", ctx => {
  ctx.body = "测试缓存";
});
/*******************强缓存****************************/

/**
 * 强缓存 => 首先从浏览器的磁盘中寻找如果有,则消耗0kb流量直接返回缓存里面的数据
 * 如果没有则发送请求
 * 最大的缺陷 => 只要时间一到,无论变化没有都会重新向服务器发送请求
 */

/**
 * 利用expires => 利用缓存到期时间 在响应消息头中 请求资源前浏览器会用当前时间与其值对比
 * 缺点:用户修改本地时间会导致失效
 */
cacheRouter.get("/expires", async ctx => {
  ctx.set("Expires", new Date(Date.now() + 10000).toUTCString());
  ctx.body = await Mock.mock({
    title: "强缓存:expires",
    "list|5-10": [
      {
        name: "@cname(2,3)",
        "id|+1": 1,
        address: "@county(true)"
      }
    ]
  });
});

/**
 * cache-control => 相对时间使用缓存资源
 * max-age => 相当于请求的到期时间
 * 还有一些别的参数
 */

cacheRouter.get("/cacheControl", async ctx => {
  ctx.set("cache-control", "max-age=10");
  ctx.body = await Mock.mock({
    title: "强缓存:cache-control",
    "list|5-10": [
      {
        name: "@cname(2,3)",
        "id|+1": 1,
        address: "@county(true)"
      }
    ]
  });
});

/****************************协商缓存******************************/

/**
 *  先看有没有备份,没有备份就去重新请求
 *  如果有备份,先问问服务器是不是最新的,发送请求头(1kb左右),服务端回复(1kb)响应头则使用本地备份;
 *  若返回新的数据(10kb)和响应头(1kb)则使用服务器最新数据
 */

/**
 * Last-Modified => 由服务器返回给客户端关于请求资源的最近修改时间(GMT标准格式)
 * if-Modified-Since => 请求值,由客户端发送给服务端上次返回的资源修改的时间
 *
 * 缺点:
 * 1.如果是以秒为单位 => 资源在1s内修改多次,由于1s内last-modified并未改变,客户端仍然使用缓存
 * 2.如果在服务器上请求的资源(a.js)被修改了但其实际内容根本没发生改变;
 * 会因为 Last-Modified 时间匹配不上而重新返回 a.js 给浏览器(举例:服务器动态生成文件)
 *
 *
 */
cacheRouter.get("/modified", ctx => {
  let pathname = `${__dirname}/string.txt`;
  // 省略其他代码
  let stat = fs.statSync(pathname);
  const data = fs.readFileSync(pathname).toString();
  if (ctx.header["if-modified-since"] === stat.mtime.toUTCString()) {
    ctx.status = 304;
  } else {
    ctx.set("Last-Modified", stat.mtime.toUTCString());
  }
  ctx.body = data;
});

/**
 *
 * ETag => 一般由last_modified与content_length组成
 * 请求方式和上面的一模一样
 * 为了解决上面的缺点
 */
cacheRouter.get("/eTag", ctx => {
  let pathname = `${__dirname}/string.txt`;
  // 省略其他代码
  let stat = fs.statSync(pathname);
  const data = fs.readFileSync(pathname).toString();
  let Etag = `${data.length.toString(16)}${stat.mtime.toString(16)}`;
  if (
    ctx.header["if-none-match"] === Etag ||
    ctx.header["if-modified-since"] === stat.mtime.toUTCString()
  ) {
    ctx.status = 304;
  } else {
    ctx.set("ETag", Etag);
  }
  ctx.body = data;
});

/**
 *  缓存优先级
 *  1.强缓存与协商缓存同时存在,强缓存还在生效期则使用强缓(强缓>协商缓存)
 *  2.在强缓存中expires > cache-control
 *  3.协商缓存中 ETag > Last-Modified
 */

router.use("/cache", cacheRouter.routes());

module.exports = router.routes();

前端demo.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>测试</title>
  </head>
  <body>
    <div id="app">
      <h1 style="text-align: center;">{{title}}</h1>
      <ul>
        <li v-for="item in list" :key="item.id">
          {{item.name}} | {{item.address}}
        </li>
      </ul>
      <button @click="query()">重新请求</button>
    </div>
  </body>
</html>
<script src="../../static/lib/axios.min.js"></script>
<script src="../../static/lib/vue-min.js"></script>
<script>
  new Vue({
    el: "#app",
    data() {
      return {
        list: [],
        title: "",
        time: ""
      };
    },
    mounted() {
      this.query();
    },
    methods: {
      // url http://192.168.50.226:8888/cache/expires
      // url http://192.168.50.226:8888/cache/cacheControl
      // url http://192.168.50.226:8888/cache/modified
      // url http://192.168.50.226:8888/cache/eTag
      query() {
        axios
          .get("http://192.168.50.226:8888/cache/eTag", {
            headers: {
              "if-none-match": this.time ? this.time : undefined
            }
          })
          .then(res => {
            console.log(111, res.request.getAllResponseHeaders());
            this.time = res.headers["Etag"];
            this.list = res.data.list;
            this.title = res.data.title;
          });
      }
    }
  });
</script>