对比(协商)缓存
比较一下再去决定是用缓存还是重新获取数据,这样会减少网络请求,提高性能。
对比缓存的工作原理
客户端第一次请求服务器的时候,服务器会把数据进行缓存,同时会生成一个缓存标识符,这个缓存标识符会被发送到客户端,客户端第二次请求服务器的时候,会把缓存标识符发送到服务器,服务器会根据缓存标识符进行判断,如果缓存标识符相同,则服务器会判断缓存是否过期,如果没有过期,则服务器会返回 304,告诉客户端使用缓存,如果缓存标识符不同,则服务器会返回 200,同时返回新的数据。
上一节使用了修改时间的方式,这一节用内容来处理
使用 md5 摘要算法:不是加密算法(不可逆)
- 不可逆
- 不同内容转化的结果不相同
- 转化后的结果都是一样长的
- 同样的东西产生的结果肯定是相同的
- 雪崩效应,一点不同翻天覆地不同
使用的库是 crypto 这个库
const crypto = require('crypto');
console.log(crypto.createHash('md5').update('kaimo313').digest('base64'));
// rFDqro5Lox3vFXr5fA4r7Q==
- 客户端:
if-none-match
- 服务端:
ETag
当前文件唯一标识
ETag + if-none-match
可以实现对比缓存,比较的方式比较精准,缺点是文件很大性能就很差,但是默认我们不会完整内容生成 hash 戳,可以取文件的某一部分,为了保证精确度,可采用内容的一部分加上文件的总大小来生成 hash 戳,这样性能会好很多。
新建 cache.js
const http = require("http");
const fs = require("fs");
const path = require("path");
const url = require("url");
const crypto = require("crypto");
const server = http.createServer((req, res) => {
const { pathname } = url.parse(req.url);
const filePath = path.join(__dirname, pathname);
console.log(req.headers);
res.setHeader("Cache-Control", "no-cache");
// 拿到客户端传过来的 if-none-match 文件标识
let ifNoneMatch = req.headers["if-none-match"];
fs.stat(filePath, (err, statObj) => {
if (err) return res.end();
// 进行文件摘要产生hash
let contentHash = crypto.createHash("md5").update(fs.readFileSync(filePath)).digest("base64");
if (ifNoneMatch === contentHash) {
res.statusCode = 304;
return res.end();
}
res.setHeader("ETag", contentHash);
// 第一请求,需要根据内容生成一个唯一的标识:可以对应当前的文件
if (err) return (res.statusCode = 404), res.end("Not Found");
// 判断是否是文件
if (statObj.isFile()) {
fs.createReadStream(filePath).pipe(res);
} else {
res.statusCode = 404;
res.end("Not Found");
}
});
});
server.listen(5000);
然后新建 public 文件夹,里面添加 index.html
和 style.css
<!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>
<link rel="stylesheet" href="/public/style.css">
</body>
</html>
body {
background-color: seagreen;
}
我们启动服务,访问 http://127.0.0.1:5000/public/index.html
,可以看到第二次请求的资源变成了 304
nodemon cache.js