对比(协商)缓存
比较一下再去决定是用缓存还是重新获取数据,这样会减少网络请求,提高性能。
对比缓存的工作原理
客户端第一次请求服务器的时候,服务器会把数据进行缓存,同时会生成一个缓存标识符,这个缓存标识符会被发送到客户端,客户端第二次请求服务器的时候,会把缓存标识符发送到服务器,服务器会根据缓存标识符进行判断,如果缓存标识符相同,则服务器会判断缓存是否过期,如果没有过期,则服务器会返回 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