72 # http 缓存策略

这篇具有很好参考价值的文章主要介绍了72 # http 缓存策略。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前面实现了一个 http-server,并且实现了 gzip 的压缩,下面通过前面几节学习的缓存知识来添加一下缓存。

大致就是先强制缓存 10s,然后采用协商(对比)缓存,大致图如下
72 # http 缓存策略,Node / Node 框架,前端工程架构,http,缓存,网络协议,强制缓存,协商缓存
在之前的 http-server 的代码基础上添加 cache 方法的实现,实现如下:

// 核心模块
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"); // 服务端读取目录进行渲染
const mime = require("mime");
const chalk = require("chalk");
const debug = require("debug")("server");
// 根据环境变量来进行打印 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 进行一次转义,避免访问中文名称文件找不到问题
        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")) {
            // 给响应头添加内容编码类型头,告诉浏览器内容是什么编码类型
            res.setHeader("Content-Encoding", "gzip");
            // 创建转化流
            return require("zlib").createGzip();
        } else {
            return false;
        }
    }
    // 设置缓存
    async cache(req, res, filePath, statObj) {
        // 先设置强制缓存
        res.setHeader("Expires", new Date(Date.now() + 10 * 1000).toGMTString());
        res.setHeader("Cache-Control", "max-age=10");
        // 再设置协商缓存
        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();
        }
        // 设置类型
        res.setHeader("Content-type", mime.getType(filePath) + ";charset=utf-8");
        // 读取文件进行响应
        // 先判断浏览器是否支持 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;

我们启动服务

kaimo-http-server

72 # http 缓存策略,Node / Node 框架,前端工程架构,http,缓存,网络协议,强制缓存,协商缓存

访问: http://localhost:3000/public/index.html

72 # http 缓存策略,Node / Node 框架,前端工程架构,http,缓存,网络协议,强制缓存,协商缓存
我们立即刷新,可以看到强制缓存

72 # http 缓存策略,Node / Node 框架,前端工程架构,http,缓存,网络协议,强制缓存,协商缓存

过了 10s 再次刷新我们可以看到变成协商缓存

72 # http 缓存策略,Node / Node 框架,前端工程架构,http,缓存,网络协议,强制缓存,协商缓存文章来源地址https://www.toymoban.com/news/detail-679451.html

到了这里,关于72 # http 缓存策略的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 前端面试中经常提到的LRU缓存策略详解

    🐱 个人主页: 不叫猫先生 🙋‍♂️ 作者简介:2022年度博客之星前端领域TOP 2,前端领域优质作者、阿里云专家博主,专注于前端各领域技术,共同学习共同进步,一起加油呀! 💫优质专栏:vue3从入门到精通、TypeScript从入门到实践 📢 资料领取:前端进阶资料以及文中源

    2024年01月16日
    浏览(37)
  • 前端删除node-module和清除缓存的方法

    1、删除node modules文件 前端删除node_modules包,可以右键一键删除,但是当包体积很大时,就会要删除很久,这时候可以使用命令行进行删除,可以跟快删掉node_modules包。命令如下: 2、清除npm缓存

    2024年02月11日
    浏览(52)
  • 前端性能优化之HTTP缓存

    前端缓存可分为两大类: HTTP 缓存 和 浏览器缓存 。 我们今天重点是 HTTP 缓存 ,下面这张图是前端缓存的一个大致知识点: 首先解决困扰绕人们的老大难问题: 一、什么是HTTP缓存? HTTP 缓存会存储与请求关联的响应,并将存储的响应复用于后续请求。(MDN) 通俗的讲,HTTP

    2024年02月06日
    浏览(75)
  • 前端浏览器缓存知识梳理,前端工程师面试题目和答案

    所谓浏览器缓存其实就是指在本地使用的计算机中开辟一个内存区,同时也开辟一个硬盘区作为数据传输的缓冲区,然后用这个缓冲区来暂时保存用户以前访问过的信息。 浏览器缓存过程:  强缓存,协商缓存。 浏览器缓存位置一般分为四类:  Service Worker–Memory Cache–Di

    2024年04月15日
    浏览(52)
  • 前端node.js入门-前端工程化与模块化

    (创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹) 目录 Node.js 入门  什么是 Node.js? 什么是前端工程化?   Node.js 为何能执行 JS?  fs 模块 - 读写文件  path 模块 - 路径处理 URL 中的端口号  常见的服务程序  Node.js 模块化 什

    2024年02月14日
    浏览(86)
  • 前端通信(渲染、http、缓存、异步、跨域)自用笔记

    目录 请求头,响应头 HTTP版本、状态码 web安全 浏览器缓存、本地存储 SSR/CSR:HTML拼接?网页源码?SEO/交互性 解析url  合成 URL-本地缓存/拦截请求-DNS解析IP/端口号(域名缓存) TCP-HTTP请求 同步 js标签跨域、url 异步 web-worker(创建分线程):适用于计算密集型任务 index.js为加

    2024年02月11日
    浏览(36)
  • 前端通信(解析url、异步、跨域、http、缓存、安全)自用笔记

    目录 请求头,响应头 HTTP版本、状态码 web安全 浏览器缓存、本地存储 SSR/CSR:HTML拼接?网页源码?SEO/交互性 解析url  合成 URL-本地缓存/拦截请求-DNS解析IP/端口号(域名缓存) TCP-HTTP请求 同步 js标签跨域、url 异步 web-worker(创建分线程):适用于计算密集型任务 index.js为加

    2024年01月24日
    浏览(43)
  • 计算机网络—HTTP基本概念、HTTPS、HTTP状态码、HTTP缓存、HTTP请求

    参考小林coding HTTP是超文本传输协议。所谓的超文本,就是超越了普通文本的文本,最关键的是有超链接,能从一个超文本跳转到另一个超文本。 HTML是最常见的超文本,本身是纯文字文件,但是内部使用很多标签定义图片、视频等链接,再经过浏览器的解释,呈现出来的就是

    2024年02月07日
    浏览(49)
  • 【计算机网络】网络安全,HTTP协议,同源策略,cors,jsonp

    ❤️ Author: 老九 ☕️ 个人博客:老九的CSDN博客 🙏 个人名言:不可控之事 乐观面对 😍 系列专栏: 会生成一个公钥一个私钥,我现在有一个东西,我用公钥给它加密,公钥可以公开给任何一个人,只有对应的私钥可以解密;如果用对称加密最重要的坏处就是需要在网络上

    2024年02月07日
    浏览(51)
  • 【热门前端【vue框架】】——vue框架和node.js的下载和安装保姆式教程

    👨‍💻个人主页 :@程序员-曼亿点 👨‍💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍💻 本文由 曼亿点 原创 👨‍💻 收录于专栏 :vue框架开发   Vue.js 是一款流行的 JavaScript 前端框架,它以其简单、灵活和高效的特性,成为了构建现代化 Web 应用程序的首选工具

    2024年04月27日
    浏览(56)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包