前面實(shí)現(xiàn)了一個 http-server
,并且實(shí)現(xiàn)了 gzip 的壓縮,下面通過前面幾節(jié)學(xué)習(xí)的緩存知識來添加一下緩存。
大致就是先強(qiáng)制緩存 10s,然后采用協(xié)商(對比)緩存,大致圖如下
在之前的 http-server
的代碼基礎(chǔ)上添加 cache 方法的實(shí)現(xiàn),實(shí)現(xiàn)如下:
// 核心模塊
const http = require("http");
const path = require("path");
const url = require("url");
const fs = require("fs").promises;
const crypto = require("crypto");
const { createReadStream, createWriteStream, readFileSync } = require("fs");
// 第三方模塊
const ejs = require("ejs"); // 服務(wù)端讀取目錄進(jìn)行渲染
const mime = require("mime");
const chalk = require("chalk");
const debug = require("debug")("server");
// 根據(jù)環(huán)境變量來進(jìn)行打印 process.env.EDBUG
debug("hello kaimo-http-server");
// 同步讀取模板
const template = readFileSync(path.resolve(__dirname, "template.ejs"), "utf-8");
class Server {
constructor(config) {
this.host = config.host;
this.port = config.port;
this.directory = config.directory;
this.template = template;
}
async handleRequest(req, res) {
let { pathname } = url.parse(req.url);
// 需要對 pathname 進(jìn)行一次轉(zhuǎn)義,避免訪問中文名稱文件找不到問題
console.log(pathname);
pathname = decodeURIComponent(pathname);
console.log(pathname);
// 通過路徑找到這個文件返回
let filePath = path.join(this.directory, pathname);
console.log(filePath);
try {
// 用流讀取文件
let statObj = await fs.stat(filePath);
// 判斷是否是文件
if (statObj.isFile()) {
this.sendFile(req, res, filePath, statObj);
} else {
// 文件夾的話就先嘗試找找 index.html
let concatFilePath = path.join(filePath, "index.html");
try {
let statObj = await fs.stat(concatFilePath);
this.sendFile(req, res, concatFilePath, statObj);
} catch (e) {
// index.html 不存在就列出目錄
this.showList(req, res, filePath, statObj, pathname);
}
}
} catch (e) {
this.sendError(req, res, e);
}
}
// 列出目錄
async showList(req, res, filePath, statObj, pathname) {
// 讀取目錄包含的信息
let dirs = await fs.readdir(filePath);
console.log(dirs, "-------------dirs----------");
try {
let parseObj = dirs.map((item) => ({
dir: item,
href: path.join(pathname, item) // url路徑拼接自己的路徑
}));
// 渲染列表:這里采用異步渲染
let templateStr = await ejs.render(this.template, { dirs: parseObj }, { async: true });
console.log(templateStr, "-------------templateStr----------");
res.setHeader("Content-type", "text/html;charset=utf-8");
res.end(templateStr);
} catch (e) {
this.sendError(req, res, e);
}
}
gzip(req, res, filePath, statObj) {
if (req.headers["accept-encoding"] && req.headers["accept-encoding"].includes("gzip")) {
// 給響應(yīng)頭添加內(nèi)容編碼類型頭,告訴瀏覽器內(nèi)容是什么編碼類型
res.setHeader("Content-Encoding", "gzip");
// 創(chuàng)建轉(zhuǎn)化流
return require("zlib").createGzip();
} else {
return false;
}
}
// 設(shè)置緩存
async cache(req, res, filePath, statObj) {
// 先設(shè)置強(qiáng)制緩存
res.setHeader("Expires", new Date(Date.now() + 10 * 1000).toGMTString());
res.setHeader("Cache-Control", "max-age=10");
// 再設(shè)置協(xié)商緩存
let fileContent = await fs.readFile(filePath);
// 指紋
let ifNoneMatch = req.headers["if-none-match"];
let etag = crypto.createHash("md5").update(fileContent).digest("base64");
// 修改時間
let ifModifiedSince = req.headers["if-modified-since"];
let ctime = statObj.ctime.toGMTString();
res.setHeader("Last-Modified", ctime);
res.setHeader("ETag", etag);
// 文件變動了就不緩存,讀取新文件
if (ifNoneMatch !== etag) {
return false;
}
if (ifModifiedSince !== ctime) {
return false;
}
return true;
}
// 讀取文件返回
async sendFile(req, res, filePath, statObj) {
// 緩存
let cache = await this.cache(req, res, filePath, statObj);
// 有緩存直接讓用戶查找緩存即可
if (cache) {
res.statusCode = 304;
return res.end();
}
// 設(shè)置類型
res.setHeader("Content-type", mime.getType(filePath) + ";charset=utf-8");
// 讀取文件進(jìn)行響應(yīng)
// 先判斷瀏覽器是否支持 gzip 壓縮
let gzip = this.gzip(req, res, filePath, statObj);
if (gzip) {
createReadStream(filePath).pipe(gzip).pipe(res);
} else {
createReadStream(filePath).pipe(res);
}
}
// 專門處理錯誤信息
sendError(req, res, e) {
debug(e);
res.statusCode = 404;
res.end("Not Found");
}
start() {
const server = http.createServer(this.handleRequest.bind(this));
server.listen(this.port, this.host, () => {
console.log(chalk.yellow(`Starting up kaimo-http-server, serving ./${this.directory.split("\\").pop()}\r\n`));
console.log(chalk.green(` http://${this.host}:${this.port}`));
});
}
}
module.exports = Server;
我們啟動服務(wù)
kaimo-http-server
訪問: http://localhost:3000/public/index.html
我們立即刷新,可以看到強(qiáng)制緩存
過了 10s 再次刷新我們可以看到變成協(xié)商緩存文章來源:http://www.zghlxwxcb.cn/news/detail-679451.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-679451.html
到了這里,關(guān)于72 # http 緩存策略的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!