對比(協商)緩存
比較一下再去決定是用緩存還是重新獲取數據,這樣會減少網絡請求,提高性能。
對比緩存的工作原理
客戶端第一次請求服務器的時候,服務器會把數據進行緩存,同時會生成一個緩存標識符,這個緩存標識符會被發送到客戶端,客戶端第二次請求服務器的時候,會把緩存標識符發送到服務器,服務器會根據緩存標識符進行判斷,如果緩存標識符相同,則服務器會判斷緩存是否過期,如果沒有過期,則服務器會返回 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();// 進行文件摘要產生hashlet 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