Http 缓存


http缓存的作用

在任何一个前端项目中,访问服务器获取数据都是很常见的事情,但是如果相同的数据被多次请求,那么多余的请求必然会浪费网络带宽,以及延迟浏览器渲染所要处理的内容。如果是按照流量计费的访问网络,那么还要浪费资源。


缓存的技术

缓存大概的可以分为共享缓存和私有缓存。

  • 共享缓存:可以被多个用户使用,比如公司内部的 web代理 ,网关缓存,负载均衡器,网关缓存
  • 私有缓存:指的是只能被单个的用户使用,如浏览器缓存

HTTP 缓存

http 缓存是前端开发中最常见的缓存机制之一,它又可细分为 强制缓存协商缓存

  • 强制缓存,就是浏览器只要访问,就从缓冲中取,不需要缓存有没有过期,不需要访问服务器
  • 协商缓存,浏览器要访问之前,需要和后端有个交互,如果后端表示数据没有变化,就直接使用原有数据

强制缓存

强制缓存,就是浏览器给服务器发送了一个请求,服务器把数据给浏览器,并且告诉浏览器,他可以对这部分数据进行强制缓存,那么浏览器再次请求的时候,如果发现原来的数据还没有过期,也就是小于时间戳 expires 的值,这样就可以直接使用原来数据,而无需做新的请求。

1.使用 expires

html界面如下:
<!DOCTYPE html>
<html lang="cn">

<head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width,initial-scale=1.0">
   <meta http-equiv="X-UA-Compatible" content="ie=edge">
   <script src="https://cdn.bootcss.com/vue/2.6.10/vue.js"></script>
   <title>Document</title>
</head>

<body>
   <h1>HTTP缓存</h1>
   <img width="300" src="./img/01.jpg" alt="青岛">
</body>

</html>
const http = require("http");
const fs = require("fs");
const url = require("url");

http.createServer((req, res) => {
    console.log(req.method, req.url);
    const {
        pathname
    } = url.parse(req.url);
    if (pathname === "/") {
        const data = fs.readFileSync('./index.html')
        res.end(data)
    } else if (pathname === "/img/01.jpg") {
        const data = fs.readFileSync('./img/01.jpg');
        res.writeHead(200,{
            // 使用过期的强制缓存时间。
            Expires:new Date("2021-5-13 12:17:57").toUTCString()
        });
        res.end(data);
    } else {
        res.statusCode = 404;
        res.end();
    }
}).listen(3000, () => {
    console.log("http server//localhost:3000");
})

命令行执行 nodemon 运行代码。

在这里插入图片描述


强制缓存的问题

使用过期时间:因为客户端和服务器的时间不一致,所以很容易出问题。

使用 cache-control 这个时间。

cache-control: "max-age=5" // 他给的是一个秒,客户端接受到数据的时间为准

 互斥的,只能选择一个
"no-cache" // 强制进行协商缓存
"no-store" //不缓存

// private 和 public
"public" // 可以被浏览器和公共缓存
private: // 默认设置,只能浏览器缓存

max-age
s-maxage //单独设计代理服务器的过期时间
在这里插入代码片
  • 对于应用程序,不会改变的文件,比如CSS 和 js 文件,可以通过发送响应头前缀添加积极缓存public


协商缓存

协商缓存,就是使用本地缓存之前,需要向服务器端,发送一次Get 请求,看之前保存的数据是否更新。

  const data = fs.readFileSync('./img/01.jpg');
        const {
            mtimes
        } = fs.statSync('./img/01.jpg'); // 读取他的最后修改时间,

        // 读取缓存的最后修改时间
        const ifmodifiedsinece = req.headers['if-modified-since'];
        if (ifmodifiedsinece === mtime.toUTCString()) { // 比较一下两个时间是否相等
            res.statusCode = 304; // 如果没过期的话,直接返回304状态码
            res.end();
            return;
        }


        res.setHeader('Cache-Control', 'no-cache');
        res.setHeader('last-modified', mtimes.toUTCString()); // 给他设置一个最后的修改时间
        res.end(data);



使用 ETag 进行协商缓存

使用 ETag 的头部信息,即实例标签(Entity Tag),

其主要是服务器为不同的资源进行哈希运算,所生成的一个字符串,该字符串类似于文件的指纹,只要文件的内容编码存在差异,对应的ETag 标签就会不同,因此可以使用 ETag 进行协商缓存。

  • 将前后端算出来的 hash 字符串进行对比。
  • 强验证,就是根据资源的内容进行验证。
  • 弱缓存,根据部分的内容进行验证。

Etag 并不是 cache-controller 的一个替代品,应该是他的一个补充,因为etag 计算的话,本身的性能开销就会很大,所有生成 ETag 的过程就会影响服务器的性能。

强制缓存的优先级是高于协商缓存的?


具体的缓存策略选择

具体的缓存方式要根据时间时间进行修改。

  • 对图片进行修改的时候,可以使用强制缓存
  • 对于样式表,使用css 的指纹,为添加了指纹,所以访问的 url 肯定不同,所以必然要对资源进行重新请求,这样可以 强制缓存和文件指纹结合使用。
  • js 也只要类似的功能就可以了

所以对文件的缓存,最好使用 强制缓存,协商缓存,和文件指纹和版本号相结合



缓存外的解决方案

  • 源码拆分,分包加载
  • 控制中间代理的缓存
  • 避免网址的冗余



缓存存放的地点

  • 如果经常使用的话,就缓存在内存里
  • 如果不经常使用的话,就缓存在磁盘里
posted @ 2021-05-13 20:53  沧海一声笑rush  阅读(51)  评论(0编辑  收藏  举报