当前位置: 首页 > Web前端 > JavaScript

废话不多说,代码实践带你掌握强缓存和协商缓存!

时间:2023-03-27 17:18:24 JavaScript

序大家好,我是林三鑫。用最通俗易懂的语言解释最难的知识点是我的座右铭。基础是进阶的前提。HTTP缓存很重要,体现在两个方面:开发:合理使用HTTP缓存可以提高前端页面的性能面试中:HTTP缓存是面试中经常被问到的问题,就不说了本篇废话,我将通过Nodejs的简单实践,告诉大家最通俗易懂的HTTP缓存,大家通过本文就能理解并掌握!!!前期准备准备创建文件夹cache-study,准备环境npminit安装Koa,nodemonnpmikoa-Dnpminodemon-gcreateindex.js,index.html,static文件夹index.html文档body>

static/css/index.css.box{width:500px;height:300px;background-image:url('../图片/guang.jpg');背景大小:100%100%;颜色:#000;}static/image/guang.jpgindex.jsconstKoa=require('koa')constfs=require('fs')constpath=require('path')constmimes={css:'text/css',less:'text/css',gif:'image/gif',html:'text/html',ico:'image/x-icon',jpeg:'image/jpeg',jpg:'image/jpeg',js:'text/javascript',json:'application/json',pdf:'application/pdf',png:'image/png',svg:'image/svg+xml',swf:'application/x-shockwave-flash',tiff:'image/tiff',txt:'text/plain',wav:'audio/x-wav',wma:'audio/x-ms-wma',wmv:'video/x-ms-wmv',xml:'text/xml',}//获取文件的类型functionparseMime(url){//path.extname获取路径中文件的后缀名让extName=路径。分机名(网址)分机名=分机名?extName.slice(1):'unknown'returnmimes[extName]}//将文件转换成传输需要的格式constparseStatic=(dir)=>{returnnewPromise((resolve)=>{resolve(fs.readFileSync(dir),'binary')})}constapp=newKoa()app.use(async(ctx)=>{consturl=ctx.request.urlif(url==='/'){//访问根路径返回index.htmlctx.set('Content-Type','text/html')ctx.body=awaitparseStatic('./index.html')}else{constfilePath=path.resolve(__dirname,`.${url}`)//设置类型ctx.set('Content-Type',parseMime(url))//设置传输ctx.body=awaitparseStatic(filePath)}})app.listen(9898,()=>{console.log('startatport9898')})Startpage现在可以在终端输入nodemonindex,看到如下显示,说明服务启动成功。这时可以在浏览器链接中输入http://localhost:9898/,打开看到如下页面,即表示页面访问成功!!!HTTP缓存的类型HTTP缓存有两种常见类型:强缓存:可以由这两个字段之一来确定expirescache-control(优先级较高)协商缓存:可以由这两对字段之一来确定Last-Modified,If-Modified-SinceEtag,If-None-Match(更高优先级)strongcache接下来开始讲strongcacheexpires。我们只需要将响应头中的过期时间设置为当前时间+30s。app.use(async(ctx)=>{consturl=ctx.request.urlif(url==='/'){//访问根路径并返回index.htmlctx.set('Content-Type','text/html')ctx.body=awaitparseStatic('./index.html')}else{constfilePath=path.resolve(__dirname,`.${url}`)//设置类型ctx.set('Content-Type',parseMime(url))//设置Expires响应头consttime=newDate(Date.now()+30000).toUTCString()ctx.set('Expires',time)//设置传输ctx.body=awaitparseStatic(filePath)}})然后我们刷新前端页面,我们可以看到请求资源的响应头中有一个expires字段,并且在30s内,我们刷新后,看到请求全部在内存中,也就是说通过expires设置强缓存的时限是30s,30s内,资源会去本地缓存,不会重新请求注意:有时候你的Nodejs代码更新了老化时间,却发现前端页面还在上次的代码老化时间,这个时候,可以勾选这个Disabledcache,然后Refresh,然后取消勾选cache-control其实cache-control和expires类似,只是这两个字段设置的值不同而已。前者设置秒数,后者设置毫秒数app.use(async(ctx)=>{consturl=ctx.request.urlif(url==='/'){//访问根路径并返回index.htmlctx.set('Content-Type','text/html')ctx.body=awaitparseStatic('./index.html')}else{constfilePath=path.resolve(__dirname,`.${url}`)//设置类型ctx.set('Content-Type',parseMime(url))//设置Cache-Control响应头ctx.set('Cache-Control','max-age=30')//设置传输ctx.body=awaitparseStatic(filePath)}})前端页面响应头添加cache-control字段,30s内会使用本地缓存,服务端不会被请求协商缓存。与强缓存不同的是,强缓存是在时间限制内,不使用服务器,只使用本地缓存;和协商缓存是采取在服务器端,如果你请求某个资源,当你请求服务器,发现命中了缓存,就会返回304,否则返回请求的资源,那怎么算命中了缓存呢?接下来说说Last-Modified,If-Modified-Since简单来说就是:第一次请求资源时,服务端会把请求资源的最后修改时间作为响应头中Last-Modified的值发送给浏览器浏览器并保存在浏览器中,当第二次请求资源时,浏览器会将刚刚存储的时间作为请求头中If-Modified-Since的值,发送给服务器,服务器会拿到这个时间和请求的资源,如果两次相同,说明资源没有被修改,也就是命中了缓存,然后返回304,如果不相同,说明资源已被修改,缓存未命中。然后返回修改后的新资源//获取文件信息constgetFileStat=(path)=>{returnnewPromise((resolve)=>{fs.stat(path,(_,stat)=>{resolve(stat)})})}app.use(async(ctx)=>{consturl=ctx.request.urlif(url==='/'){//访问根路径并返回index.htmlctx.set('Content-Type','text/html')ctx.body=awaitparseStatic('./index.html')}else{constfilePath=path.resolve(__dirname,`.${url}`)constifModifiedSince=ctx.请求.header['if-modified-since']constfileStat=awaitgetFileStat(filePath)console.log(newDate(fileStat.mtime).getTime())ctx.set('Cache-Control','no-cache')ctx.set('内容t-Type',parseMime(url))//比较时间,mtime为文件最后修改时间if(ifModifiedSince===fileStat.mtime.toGMTString()){ctx.status=304}else{ctx.set('Last-Modified',fileStat.mtime.toGMTString())ctx.body=awaitparseStatic(filePath)}}})在第一个请求中,在响应头中:在第二个请求中,在请求头中:因为资源未修改,命中缓存返回304:此时我们修改index.css.box{width:500px;高度:300px;背景图片:url('../image/guang.jpg');背景大小:100%100%;/*修改这里*/color:#333;}然后我们刷新页面,index.css发生了变化,所以会错过缓存,返回200和新的资源,而guang.jpg没有被修改,然后命中缓存返回304:Etag,If-None-Match其实Etag,If-None-Match和Last-Modified,If-Modified-Since大致相同,不同的是后者比较资源的最后修改时间来判断资源是否被修改前者通过比较资源内容来判断资源是否被修改,那么我们如何比较资源内容呢?我们只需要读取资源的内容,转换成哈希值,前后对比即可!!constcrypto=require('crypto')app.use(async(ctx)=>{consturl=ctx.request.urlif(url==='/'){//访问根路径并返回index.htmlctx.set('Content-Type','text/html')ctx.body=awaitparseStatic('./index.html')}else{const文件路径=path.resolve(__dirname,`.${url}`)constfileBuffer=awaitparseStatic(filePath)constifNoneMatch=ctx.request.header['if-none-match']//产生内容哈希值consthash=crypto.createHash('md5')hash.update(fileBuffer)constetag=`"${hash.digest('hex')}"`ctx.set('Cache-Control','no-cache')ctx.set('Content-Type',parseMime(url))//比较哈希值if(ifNoneMatch===etag){ctx.status=304}else{ctx.set('etag',etag)ctx.body=fileBuffer}}})校验方式和刚才的Last-Modified和If-Modified-Since一样,这里不再赘述。.总结参考https://blog.csdn.net/qq_3243...结语我是林三鑫,一个狂热的前端菜鸟程序员。如果你有上进心,喜欢前端,想学前端,那我们可以交个朋友,一起钓鱼哈哈,摸摸鱼群,加我,请注意[思想]