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
也只要类似的功能就可以了
所以对文件的缓存,最好使用 强制缓存,协商缓存,和文件指纹和版本号相结合
缓存外的解决方案
- 源码拆分,分包加载
- 控制中间代理的缓存
- 避免网址的冗余
缓存存放的地点
- 如果经常使用的话,就缓存在内存里
- 如果不经常使用的话,就缓存在磁盘里