node中的缓存机制

缓存是node开发中一个很重要的概念,它应用在很多地方,例如:浏览器有缓存、DNS有缓存、包括服务器也有缓存。

一、缓存作用

那缓存是为了做什么呢?

1.为了提高速度,提高效率。

2.减少数据传输,节省网费。

3.减少服务器的负担,提高网站性能。

4.加快客户端加载网页的速度。

二、缓存分类

那缓存有几种策略呢?

强制缓存:

1、概念:

客户端访问服务器请求资源,请求成功之后客户端会缓存到本地,缓存到本地之后,如果以后客户端再请求该资源此时不需要请求服务器了,直接访问本地的就可以。

2、特点:

强制缓存不需要与服务器发生交互

3、客户端访问强制缓存的流程图解

1)缓存命中 客户端请求数据,现在本地的缓存数据库中查找,如果本地缓存数据库中有该数据,且该数据没有失效。则取缓存数据库中的该数据返回给客户端。

2)缓存未命中 客户端请求数据,现在本地的缓存数据库中查找,如果本地缓存数据库中有该数据,且该数据失效。则向服务器请求该数据,此时服务器返回该数据和该数据的缓存规则返回给客户端,客户端收到该数据和缓存规则后,一起放到本地的缓存数据库中留存。以备下次使用。

4、如何实现强制缓存?

1、浏览器会将文件缓存到Cache目录,第二次请求时浏览器会先检查Cache目录下是否含有该文件,如果有,并且还没到Expires设置的时间,即文件还没有过期,那么此时浏览器将直接从Cache目录中读取文件,而不再发送请求 2、Expires是服务器响应消息头字段,在响应http请求时告诉浏览器在过期时间前浏览器可以直接从浏览器缓存取数据,而无需再次请求,这是HTTP1.0的内容,现在浏览器均默认使用HTTP1.1,所以基本可以忽略 3、Cache-Control与Expires的作用一致,都是指明当前资源的有效期,控制浏览器是否直接从浏览器缓存取数据还是重新发请求到服务器取数据,如果同时设置的话,其优先级高于Expires

把资源缓存在客户端,如果客户端再次需要此资源的时候,先获取到缓存中的数据,看是否过期,如果过期了。再请求服务器 如果没过期,则根本不需要向服务器确认,直接使用本地缓存即可

Cache-Control private 客户端可以缓存 public 客户端和代理服务器都可以缓存 max-age=60 缓存内容将在60秒后失效 no-cache 需要使用对比缓存验证数据,强制向源服务器再次验证. 禁用强制缓存 no-store 所有内容都不会缓存,强制缓存和对比缓存都不会触发。兼用强制缓存和对比缓存å

/**
* 1. 第一次访问服务器的时候,服务器返回资源和缓存的标识,客户端则会把此资源缓存在本地的缓存数据库中。
* 2. 第二次客户端需要此数据的时候,要取得缓存的标识,然后去问一下服务器我的资源是否是最新的。
* 如果是最新的则直接使用缓存数据,如果不是最新的则服务器返回新的资源和缓存规则,客户端根据缓存规则缓存新的数据。
*/
let http = require('http');
let url = require('url');
let path = require('path');
let fs = require('fs');
let mime = require('mime');
let crypto = require('crypto');
/**
* 强制缓存
* 把资源缓存在客户端,如果客户端再次需要此资源的时候,先获取到缓存中的数据,看是否过期,如果过期了。再请求服务器
* 如果没过期,则根本不需要向服务器确认,直接使用本地缓存即可
*/
http.createServer(function (req, res) {let { pathname } = url.parse(req.url, true);let filepath = path.join(__dirname, pathname);console.log(filepath);fs.stat(filepath, (err, stat) => {if (err) {return sendError(req, res);} else {send(req, res, filepath);
}
});
}).listen(8080);
function sendError(req, res) {res.end('Not Found');
}
function send(req, res, filepath) {res.setHeader('Content-Type', mime.getType(filepath));//expires指定了此缓存的过期时间,此响应头是1.0定义的,在1.1里面已经不再使用了res.setHeader('Expires', new Date(Date.now()   30 * 1000).toUTCString());res.setHeader('Cache-Control', 'max-age=30');fs.createReadStream(filepath).pipe(res);
}

对比缓存:

1、概念:

浏览器第一次请求数据时,服务器会将缓存标识与数据一起返回给客户端,客户端将二者备份至缓存数据库中。 再次请求数据时,客户端将备份的缓存标识发送给服务器,服务器根据缓存标识进行判断,判断成功后,返回304状态码,通知客户端比较成功,可以使用缓存数据。

2、特点:需要进行比较判断是否可以使用缓存
3、对比缓存流程图解

1)客户端第一次发请求

客户端第一次请求数据,发现本地缓存中没有,就向服务器发起请求,然后服务器把请求的数据返回给客户端,并和客户端商量你要保存到本地缓存中的规则,即是否缓存 缓存时间 有没有标示 最后修改时间等信息。 2)客户端第二次发请求
客户端发起请请求 --->查看本地的缓存数据库中是否有缓存---> 没有---> 向服务器发起请求--->服务器返回200和响应内容--->显示

--->查看本地的缓存数据库中是否有缓存---> 有 ---> 缓存没有过期(本地)---> 缓存中读取--->显示

--->查看本地的缓存数据库中是否有缓存---> 有 ---> 缓存已过期(本地)---> 本地的缓存中有没有Etag和Last-Modified --->有--->发给服务器对应的字段 if-none-match 和if-modified-since ---> 服务器策略。如果这两个字段和服务器上的这两个字段相同 ---> 说明数据没有更新--->返回304--->服务器从它的缓存库中获取到数据给客户端--->显示

--->查看本地的缓存数据库中是否有缓存---> 有 ---> 缓存已过期(本地)---> 本地的缓存中有没有Etag和Last-Modified --->有--->发给服务器对应的字段 if-none-match 和if-modified-since ---> 服务器策略。如果这两个字段和服务器上的这两个字段不相同 --->说明数据有更新--->返回200--->重新获取--->显示

4、如何实现对比缓存?

/**

    1. 第一次访问服务器的时候,服务器返回资源和缓存的标识,客户端则会把此资源缓存在本地的缓存数据库中。
    1. 第二次客户端需要此数据的时候,要取得缓存的标识,然后去问一下服务器我的资源是否是最新的。
  • 如果是最新的则直接使用缓存数据,如果不是最新的则服务器返回新的资源和缓存规则,客户端根据缓存规则缓存新的数据。 */ 我们通过标示字段来判断缓存中的数据是否有效 这个标示有两种形式:
第一种是最后修改时间,Last-Modified

1、Last-Modified:响应时告诉客户端此资源的最后修改时间 2、If-Modified-Since:当资源过期时(使用Cache-Control标识的max-age),发现资源具有Last-Modified声明,则再次向服务器请求时带上头If-Modified-Since。 3、服务器收到请求后发现有头If-Modified-Since则与被请求资源的最后修改时间进行比对。若最后修改时间较新,说明资源又被改动过,则响应最新的资源内容并返回200状态码; 4、若最后修改时间和If-Modified-Since一样,说明资源没有修改,则响应304表示未更新,告知浏览器继续使用所保存的缓存文件。

let http = require('http');
let url = require('url');
let path = require('path');
let fs = require('fs');
let mime = require('mime');
// http://localhost:8080/index.html
http.createServer(function (req, res) {let {pathname} = url.parse(req.url);let filepath = path.join(__dirname,pathname);console.log(filepath);fs.stat(filepath,function (err, stat) {if (err) {return sendError(req,res)} else {// 再次请求的时候会问服务器自从上次修改之后有没有改过let ifModifiedSince = req.headers['if-modified-since'];console.log(req.headers);let LastModified = stat.ctime.toGMTString();console.log(LastModified);if (ifModifiedSince == LastModified) {res.writeHead('304');res.end('')} else {return send(req,res,filepath,stat)}}})}).listen(8080)function send(req,res,filepath,stat) {res.setHeader('Content-Type', mime.getType(filepath));// 发给客户端之后,客户端会把此时间保存下来,下次再获取此资源的时候会把这个时间再发给服务器res.setHeader('Last-Modified', stat.ctime.toGMTString());fs.createReadStream(filepath).pipe(res)
}function sendError(req,res) {res.end('Not Found')
}
最后修改时间存在问题

1、某些服务器不能精确得到文件的最后修改时间, 这样就无法通过最后修改时间来判断文件是否更新了。 2、某些文件的修改非常频繁,在秒以下的时间内进行修改. Last-Modified只能精确到秒。 3、一些文件的最后修改时间改变了,但是内容并未改变。 我们不希望客户端认为这个文件修改了。 4、如果同样的一个文件位于多个CDN服务器上的时候内容虽然一样,修改时间不一样。

第二种是Etag

ETag是实体标签的缩写,根据实体内容生成的一段hash字符串,可以标识资源的状态。当资源发生改变时,ETag也随之发生变化。 ETag是Web服务端产生的,然后发给浏览器客户端。

1、客户端想判断缓存是否可用可以先获取缓存中文档的ETag,然后通过If-None-Match发送请求给Web服务器询问此缓存是否可用。 2、服务器收到请求,将服务器的中此文件的ETag,跟请求头中的If-None-Match相比较,如果值是一样的,说明缓存还是最新的,Web服务器将发送304 Not Modified响应码给客户端表示缓存未修改过,可以使用。 3、如果不一样则Web服务器将发送该文档的最新版本给浏览器客户端

let http = require('http');
let url = require('url');
let path = require('path');
let fs = require('fs');
let mime = require('mime');
let crypto = require('let crypto = require(\'mime\');\n');
// http://localhost:8080/index.html
http.createServer(function (req, res) {let {pathname} = url.parse(req.url);let filepath = path.join(__dirname,pathname);console.log(filepath);fs.stat(filepath,function (err, stat) {if (err) {return sendError(req,res)} else {let ifNoneMatch = req.headers['if-none-match'];// 一、显然当我们的文件非常大的时候通过下面的方法就行不通来,这时候我们可以用流来解决,可以节约内存let out = fs.createReadStream(filepath);let md5 = crypto.createHash('md5');out.on('data',function (data) {md5.update(data)});out.on('end',function () {let etag = md5.update(content).digest('hex');// md5算法的特点 1. 相同的输入相同的输出 2.不同的输入不通的输出 3.不能根据输出反推输入 4.任意的输入长度输出长度是相同的if (ifNoneMatch == etag) {res.writeHead('304');res.end('')} else {return send(req,res,filepath,stat, etag)}});// 二、再次请求的时候会问服务器自从上次修改之后有没有改过// fs.readFile(filepath,function (err, content) {//     let etag = crypto.createHash('md5').update(content).digest('hex');//     // md5算法的特点 1. 相同的输入相同的输出 2.不同的输入不通的输出 3.不能根据输出反推输入 4.任意的输入长度输出长度是相同的//     if (ifNoneMatch == etag) {//         res.writeHead('304');//         res.end('')//     } else {//         return send(req,res,filepath,stat, etag)//     }// };// 但是上面的一方案也不是太好,读一点缓存一点,文件非常大的话需要好长时间,而且我们的node不适合cup密集型,即不适合来做大量的运算,所以说还有好多其他的算法// 三、通过文件的修改时间减去文件的大小// let etag = `${stat.ctime}-${stat.size}`; // 这个也不是太好// if (ifNoneMatch == etag) {//     res.writeHead('304');//     res.end('')// } else {//     return send(req,res,filepath,stat, etag)// }}})}).listen(8080)function send(req,res,filepath,stat, etag) {res.setHeader('Content-Type', mime.getType(filepath));// 第一次服务器返回的时候,会把文件的内容算出来一个标示发送给客户端//客户端看到etag之后,也会把此标识符保存在客户端,下次再访问服务器的时候,发给服务器res.setHeader('Etag', etag);fs.createReadStream(filepath).pipe(res)
}function sendError(req,res) {res.end('Not Found')
}
存在问题

都需要向服务器端发请求与服务器端发生交互


更多专业前端知识,请上 【猿2048】www.mk2048.com

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/366425.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《H5 移动营销设计指南》 读书笔记整理

一个前端工程师最近迷上了营销类的H5页面,被五花八门的H5页面迷的眼花缭乱,兴趣使然,于是买了一本《H5 营销设计指南》,看完以后对营销类的H5页面有了更深的理解,感觉很实在,所以参考读书笔记整理成PPT分享…

mysql-plus多数据库_IDEA项目搭建九——MybatisPlus多数据库实现

一、简介MybatisPlus中引用多数据库时,传统的配置就失效了,需要单独写配置来实现,下面就说一下具体应该如何操作二、引入MybatisPlus多数据源配置还是先看一下我的项目结构,Model是单独的模块,请自行创建1、创建一个Ma…

数字逻辑基础篇1

1. 双阈值准则在模拟条件下&#xff0c;假设点亮灯泡需要1.7V以上电压。抽象为数字电路&#xff0c;可以认为&#xff1a; U>1.7V U1 U<1.7V U0 这种条件称之为单阈值&#xff08;1.7&#xff09;&#xff0c;但是单阈值导致的问题是&#xff1a; 电压在1.7V附近…

Neo4j:在Neo4j浏览器的帮助下探索新数据集

当我查看一个新的Neo4j数据库时&#xff0c;发现困难之一是确定其中包含的数据的结构。 我习惯于关系数据库&#xff0c;在该数据库中您可以轻松地获取表列表和外键&#xff0c;从而使它们彼此连接。 传统上&#xff0c;使用Neo4j时很难做到这一点&#xff0c;但是随着Neo4j浏…

V8 —— 你需要知道的垃圾回收机制

前言V8 blog近日发布了文章描述了“并发标记”的新技术&#xff0c;提升标记过程的效率。并发标记是一个主要用新的平行和并发的垃圾收集器替换旧的垃圾回收器的项目&#xff0c;现在Chrome 64和Node.js v10已经默认启用并发标记。讲解之前我们先回顾一下基本知识点。基本概念 …

词法分析器java_Java代码到底是如何编译成机器指令的。

原文地址&#xff1a;https://mp.weixin.qq.com/s/XH-JajAne0O7_yCYE5wBbg作者&#xff1a;Hollis在《Java代码的编译与反编译》中&#xff0c;有过关于Java语言的编译和反编译的介绍。我们可以通过javac命令将Java程序的源代码编译成Java字节码&#xff0c;即我们常说的class文…

python中的PEP是什么?怎么理解?(转)

PEP是什么&#xff1f; PEP的全称是Python Enhancement Proposals&#xff0c;其中Enhancement是增强改进的意思&#xff0c;Proposals则可译为提案或建议书&#xff0c;所以合起来&#xff0c;比较常见的翻译是Python增强提案或Python改进建议书。 我个人倾向于前一个翻译&…

2017前端技术大盘点

前言 临近2017的尾声&#xff0c;总是希望来盘点一下这一年中前端的发展。到目前为止&#xff0c;前端的井喷期也快临近尾声了。并不像几年前一样&#xff0c;总是会有层出不穷的新东西迸发出来。同时&#xff0c;前端技术也慢慢的趋于稳固&#xff0c;自成一套体系。如果你喜…

jenkins pipeline api获取stage的详细信息_Jenkins + Docker 助力 Serverless 应用构建与部署...

本文来源&#xff1a; ServerlessLife 公众号近日&#xff0c;使用 Serverless 开发了一个应用。其中 CI/CD&#xff0c;是需要考虑的一个问题。这里用到了 Jenkins 和 Docker。并且 Jenkins Pipeline 运行在容器中。本文将介绍如何使用 Jenkins 和 Docker 构建并部署 Serverle…

项目本地部署

1.将数据库导出&#xff0c;并导入到本地 exp dgpdg/pass192.168.1.33/ORCL fileD:\gd_base.dmp logD:\gd_base.log&#xff08;不要加fully&#xff0c;会把整个数据库下所有用户的表倒下来&#xff09; imp dgpdg/pass127.0.0.1/orcl file"D:\gd_base.dmp" log&quo…

命名空间不能直接包含字段或方法之类的成员是什么意思_Python 学习笔记之类与实例...

Python 学习笔记之类与实例一、定义1.1、定义类 (class) 封装一组相关数据&#xff0c;使之成为一个整体&#xff0c;并使用一种方法持续展示和维护。这有点像把零件组装成整车提供给用户&#xff0c;无须了解汽车的内部结构和工作原理&#xff0c;只要知道方向盘&#xff0c;刹…

跨平台开发框架 Lynx 初探

跨平台开发是目前开发较热门的方向&#xff0c;React Native 在这方面取得了很大的成功&#xff0c;同时 Flutter 也获得了非常多的关注。React Native 采用 Web 框架开发并使用 Native UI 进行渲染&#xff0c;很大程度上降低了 Native 开发的门槛并且提高迭代的效率&#xff…

ajax包含mysql吗_php 实例ajax与mysql怎么只查询出一条数据?

http://www.runoob.com/php/php...使用这个实例操作之后为什么只显示一条数据&#xff0c;如何让符合条件的数据全部显示出来如&#xff0c;我使用的查询字段是yesterday_str&#xff0c;查询2017-04-18这个数据怎么样才能把2017-04-18包含这个的全部数据提取出来&#xff1f;p…

aspx写入mysql_Asp.net用户登陆数据库验证与注册写入数据库

1.思路与效果图Index.aspx注册注册成功登陆登陆验证通过进入内容页1登陆没通过验证思路&#xff1a;首先建一个Sqlserver数据库Student,再建一个student表(name,pwd)存放用户名和密码。然后注册功能的实现&#xff1a;通过数据库插入信息到表的Sql语句来实现&#xff0c;成功提…

页面体验提升小技巧—渐进式图片

前端性能方面有许多可优化的点&#xff0c;而这些优化带来的就是用户体验的提升。今天我们要聊的东西并不能给性能带来提升&#xff0c;但却能在一定程度上提升用户的体验。 参考博客 场景&#xff1a;在访问页面的时候如果图片较大或者网速慢的情况我们会看到图片加载起来是有…

微信小程序搭配小白接口,自己没有服务器也能开发哦

这里将重点介绍&#xff0c;在自己没有服务器的情况下&#xff0c;如何在微信小程序里直接调用小白接口。 前提 假设你已经开通微信小程序&#xff0c;如果还没有&#xff0c;可前往微信公众平台开通&#xff1a;https://mp.weixin.qq.com 假设你已经开通小白接口&#xff0c…

怎么将自己做好的网站发布到互联网上呢?

如何将自己的网站上传到网站空间。 1.需要有一个上传网站的软件&#xff0c;在这里推荐大家使用 FTP全称是flashfxp这个软件&#xff0c;这个功能功能齐全而且操作简单。大家可以先去下载一下这个软 件 2. 打开FTP&#xff0c;界面如下 3.我们要点击链接按钮&#xff0c;然后FT…

[贝聊科技]网页端「应用跳转」技术实现演变

本文作者&#xff1a;Mr.Luo &#xff0c;贝聊前端经理。本文同时发布于作者 个人博客 。 由于网页传播的便捷性&#xff0c;从网页向APP导流几乎是所有APP厂商都会采用的推广手段&#xff0c;具体来说就是在网页上提供一些触发点&#xff08;例如按钮、链接&#xff09;&#…

Linux服务器配置---安装vsftpd

安装vsftpd 大多数Linux系统都使用vsftpd&#xff0c;因此这里我们也安装vsftpd 1、安装vsftpd [rootlocalhost phpMyAdmin]# yum install -y vsftpd Loaded plugins: fastestmirror, refresh-packagekit, security Installed: vsftpd.i686 0:2.2.2-11.el6_4.1 …

mysql怎么制作柱状图_从数据库中取出最近三十天的数据并生成柱状图

在终端用cd 命令进入文件目录说明&#xff1a;此处例子我是拿项目中的一个例子讲解的。1、新建一个项目 &#xff1a;用终端输入&#xff1a;zf create project Airline 格式&#xff1a;zf create action project project-name 备注&#xff1a;这些格式可以在终端输入zf 查看…