不废话,代码实践带你掌握|不废话,代码实践带你掌握 强缓存、协商缓存!
admin
2023-08-16 10:35:33
0次

前言 大家好,我是林三心,用最通俗易懂的话讲最难的知识点是我的座右铭,基础是进阶的前提是我的初心
背景 无论是开发中或者是面试中,HTTP缓存都是非常重要的,这体现在了两个方面:

  • 开发中:合理利用 HTTP缓存 可以提高前端页面的性能
  • 面试中: HTTP缓存 是面试中的高频问点
所以本篇文章,我不讲废话,我就通过 Nodejs 的简单实践,给大家讲最通俗易懂的HTTP缓存,大家通过这篇文章一定能了解掌握它!!!
前置准备 准备
  • 创建文件夹 cache-study ,并准备环境
    npm init

  • 安装 Koa、nodemon
    npm i koa -D npm i nodemon -g

  • 创建 index.js、index.html、static文件夹
  • index.html
    Document

  • static/css/index.css
    .box { width: 500px; height: 300px; background-image: url('../image/guang.jpg'); background-size: 100% 100%; color: #000; }

  • static/image/guang.jpg
不废话,代码实践带你掌握|不废话,代码实践带你掌握 强缓存、协商缓存!
文章图片

  • index.js
    const Koa = require('koa') const fs = require('fs') const path = require('path') const mimes = { 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', }// 获取文件的类型 function parseMime(url) { // path.extname获取路径中文件的后缀名 let extName = path.extname(url) extName = extName ? extName.slice(1) : 'unknown' return mimes[extName] }// 将文件转成传输所需格式 const parseStatic = (dir) => { return new Promise((resolve) => { resolve(fs.readFileSync(dir), 'binary') }) }const app = new Koa()app.use(async (ctx) => { const url = ctx.request.url if (url === '/') { // 访问根路径返回index.html ctx.set('Content-Type', 'text/html') ctx.body = await parseStatic('./index.html') } else { const filePath = path.resolve(__dirname, `.${url}`) // 设置类型 ctx.set('Content-Type', parseMime(url)) // 设置传输 ctx.body = await parseStatic(filePath) } })app.listen(9898, () => { console.log('start at port 9898') })

    启动页面
    现在你可以在终端中输入 nodemon index ,看到下方的显示,则代表成功启动了服务
不废话,代码实践带你掌握|不废话,代码实践带你掌握 强缓存、协商缓存!
文章图片

此时你可以在浏览器链接里输入 http://localhost:9898/ ,打开看到如下页面,则代表页面访问成功!!!
不废话,代码实践带你掌握|不废话,代码实践带你掌握 强缓存、协商缓存!
文章图片

HTTP缓存种类 HTTP缓存 常见的有两类:
  • 强缓存 :可以由这两个字段其中一个决定
    • expires
    • cache-control(优先级更高)
  • 协商缓存 :可以由这两对字段中的一对决定
    • Last-Modified,If-Modified-Since
    • Etag,If-None-Match(优先级更高)
强缓存 接下来我们就开始讲强缓存
expires
我们只需设置响应头里 expires 的时间为 当前时间 + 30s 就行了
app.use(async (ctx) => { const url = ctx.request.url if (url === '/') { // 访问根路径返回index.html ctx.set('Content-Type', 'text/html') ctx.body = await parseStatic('./index.html') } else { const filePath = path.resolve(__dirname, `.${url}`) // 设置类型 ctx.set('Content-Type', parseMime(url)) // 设置 Expires 响应头 const time = new Date(Date.now() + 30000).toUTCString() ctx.set('Expires', time) // 设置传输 ctx.body = await parseStatic(filePath) } })

然后我们在前端页面刷新,我们可以看到请求的资源的响应头里多了一个 expires 的字段
不废话,代码实践带你掌握|不废话,代码实践带你掌握 强缓存、协商缓存!
文章图片

并且,在30s内,我们刷新之后,看到请求都是走 memory ,这意味着,通过 expires 设置强缓存的时效是30s,这30s之内,资源都会走本地缓存,而不会重新请求
不废话,代码实践带你掌握|不废话,代码实践带你掌握 强缓存、协商缓存!
文章图片

注意点:有时候你Nodejs代码更新了时效时间,但是发现前端页面还是在走上一次代码的时效,这个时候,你可以把这个 Disabled cache 打钩,然后刷新一下,再取消打钩
不废话,代码实践带你掌握|不废话,代码实践带你掌握 强缓存、协商缓存!
文章图片

cache-control
其实 cache-control 跟 expires 效果差不多,只不过这两个字段设置的值不一样而已,前者设置的是 秒数 ,后者设置的是 毫秒数
app.use(async (ctx) => { const url = ctx.request.url if (url === '/') { // 访问根路径返回index.html ctx.set('Content-Type', 'text/html') ctx.body = await parseStatic('./index.html') } else { const filePath = path.resolve(__dirname, `.${url}`) // 设置类型 ctx.set('Content-Type', parseMime(url)) // 设置 Cache-Control 响应头 ctx.set('Cache-Control', 'max-age=30') // 设置传输 ctx.body = await parseStatic(filePath) } })

前端页面响应头多了 cache-control 这个字段,且30s内都走本地缓存,不会去请求服务端
不废话,代码实践带你掌握|不废话,代码实践带你掌握 强缓存、协商缓存!
文章图片

协商缓存 与 强缓存 不同的是, 强缓存 是在时效时间内,不走服务端,只走本地缓存;而 协商缓存 是要走服务端的,如果请求某个资源,去请求服务端时,发现 命中缓存 则返回 304 ,否则则返回所请求的资源,那怎么才算 命中缓存 呢?接下来讲讲
Last-Modified,If-Modified-Since
简单来说就是:
  • 第一次请求资源时,服务端会把所请求的资源的 最后一次修改时间 当成响应头中 Last-Modified 的值发到浏览器并在浏览器存起来
  • 第二次请求资源时,浏览器会把刚刚存储的时间当成请求头中 If-Modified-Since 的值,传到服务端,服务端拿到这个时间跟所请求的资源的最后修改时间进行比对
  • 比对结果如果两个时间相同,则说明此资源没修改过,那就是 命中缓存 ,那就返回 304 ,如果不相同,则说明此资源修改过了,则 没命中缓存 ,则返回修改过后的新资源
// 获取文件信息 const getFileStat = (path) => { return new Promise((resolve) => { fs.stat(path, (_, stat) => { resolve(stat) }) }) }app.use(async (ctx) => { const url = ctx.request.url if (url === '/') { // 访问根路径返回index.html ctx.set('Content-Type', 'text/html') ctx.body = await parseStatic('./index.html') } else { const filePath = path.resolve(__dirname, `.${url}`) const ifModifiedSince = ctx.request.header['if-modified-since'] const fileStat = await getFileStat(filePath) console.log(new Date(fileStat.mtime).getTime()) ctx.set('Cache-Control', 'no-cache') ctx.set('Content-Type', parseMime(url)) // 比对时间,mtime为文件最后修改时间 if (ifModifiedSince === fileStat.mtime.toGMTString()) { ctx.status = 304 } else { ctx.set('Last-Modified', fileStat.mtime.toGMTString()) ctx.body = await parseStatic(filePath) } } })

第一次请求时,响应头中:
不废话,代码实践带你掌握|不废话,代码实践带你掌握 强缓存、协商缓存!
文章图片

第二次请求时,请求头中:
不废话,代码实践带你掌握|不废话,代码实践带你掌握 强缓存、协商缓存!
文章图片

由于资源并没修改,则命中缓存,返回304:
不废话,代码实践带你掌握|不废话,代码实践带你掌握 强缓存、协商缓存!
文章图片

此时我们修改一下 index.css
.box { width: 500px; height: 300px; background-image: url('../image/guang.jpg'); background-size: 100% 100%; /* 修改这里 */ color: #333; }

然后我们刷新一下页面, index.css 变了,所以会 没命中缓存 ,返回200和新资源,而 guang.jpg 并没有修改,则 命中缓存 返回304:
不废话,代码实践带你掌握|不废话,代码实践带你掌握 强缓存、协商缓存!
文章图片

Etag,If-None-Match
其实 Etag,If-None-Match 跟 Last-Modified,If-Modified-Since 大体一样,区别在于:
  • 后者是对比资源最后一次修改时间,来确定资源是否修改了
  • 前者是对比资源内容,来确定资源是否修改
那我们要怎么比对资源内容呢?我们只需要读取资源内容,转成hash值,前后进行比对就行了!!
const crypto = require('crypto')app.use(async (ctx) => { const url = ctx.request.url if (url === '/') { // 访问根路径返回index.html ctx.set('Content-Type', 'text/html') ctx.body = await parseStatic('./index.html') } else { const filePath = path.resolve(__dirname, `.${url}`) const fileBuffer = await parseStatic(filePath) const ifNoneMatch = ctx.request.header['if-none-match'] // 生产内容hash值 const hash = crypto.createHash('md5') hash.update(fileBuffer) const etag = `"${hash.digest('hex')}"` ctx.set('Cache-Control', 'no-cache') ctx.set('Content-Type', parseMime(url)) // 对比hash值 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...
结语 我是林三心,一个热心的前端菜鸟程序员。如果你上进,喜欢前端,想学习前端,那咱们可以交朋友,一起摸鱼哈哈,摸鱼群,加我请备注【思否】
【不废话,代码实践带你掌握|不废话,代码实践带你掌握 强缓存、协商缓存!】不废话,代码实践带你掌握|不废话,代码实践带你掌握 强缓存、协商缓存!
文章图片

相关内容

热门资讯

大浪淘金APP黑幕揭秘:内盘操...   大浪淘金APP平台最隐蔽的黑幕,在于其完全封闭的内盘交易系统。这个看似与国际市场接轨的交易平台,...
告别固定工资实现财富自由?一品...   普通投资者被广告宣传诱导,注册就送现金,充值返现金券等等这些宣传方式,都是在引流到平台开户,不怕...
哈易购APP打着现货交易幌子搞...   网络上各类白银、铂金等贵金属投资广告铺天盖地,不少平台以"现货交易"为名,暗中却从事着非法期货交...
5元起投!高额收益?中国白银、...   上海华通白银国际交易中心有限公司(以下简称“华通白银国际”)打着“白银、铂金现货订购”的旗号,实...
"九州订购APP、起...   近年来,贵金属投资热度持续攀升,但乱象也随之而来。一些不法分子趁机搭建虚假交易平台,打着"低门槛...
坚锅淘金APP投资者频繁爆仓亏...   坚锅淘金APP对外宣称是贵金属现货交易平台,日常出入金看似畅通无阻,给人一种合规运营的假象。但事...
斗金订购APP“5元订购现货”...   斗金订购APP“5元订购现货”骗局揭秘:充值易、回本难,越陷越深!  许多投资人在未核实平台合规...
贵金属APP乱象曝光:&quo...   当前市场上部分贵金属类APP未取得正规交易资质,涉嫌误导消费者参与白银、铂金等商品的非合规交易!...
华通白银、银宝街APP被指虚假...   警惕现货白银投资陷阱:上海华通白银背后的平台涉嫌非法期货交易  近年来,各类现货白银交易平台以“...
充值送300,月入过万?别被量...   如今,网络上充斥着大量未经批准的贵金属及其他产品订购交易平台。这些平台普遍缺乏合法经营资质,却将...
鑫汇智投APP贵金属非法期货、...   鑫汇智投APP贵金属非法期货、人为控盘,大量投资者遭恶意收割  鑫汇智投APP长期以“低门槛、高...
矅光智策APP非法贵金属交易骗...   不少投资人在矅光智策APP上进行贵金属交易后出现了严重亏损。许多人在下载该平台时,根本不清楚其是...
飞鸽订购APP非法期货交易骗局...   飞鸽订购APP非法期货交易骗局,很多投资者根本没搞懂规则就盲目充值,买涨买跌跟买cai票一样!平...
天龙白银APP被操控的非法期货...   中小投资者在网络平台参与商品现货订购交易,表面看似合规合法,实则暗藏诸多难以察觉的风险。商品现货...
下载送试玩金?千万别碰!带你揭...   当前,许多贵金属APP交易平台正采用欺诈性营销手段。它们通过抖音等短视频平台,以“5元起投”“充...
泡泡淘金APP骗局:打着&qu...   泡泡淘金APP骗局:打着"商品订购"幌子,实则非法期货收割投资者!投资需谨慎,切勿轻信“高额回报...
南商云购APP虚假电子盘背后的...   南商云购是虚假电子盘吗?它是否具备合规的交易资质?这个曾经的"现货电子盘"如今摇身一变,披上了"...
警惕"祥龙订购&qu...   祥龙订购APP、掌上银牛APP等平台背后的运营方——四川禄宏商品现货市场有限公司,仅具备现货交易...
中国白银、华银:虚假宣传、后台...   中国白银APP宣称是上市公司“中国白银集团”与“上海华通白银国际交易中心”旗下的现货交易平台,提...
起底“优品订购”APP非法期货...   “优品订购”APP根本不具备任何合法的交易资质。其背后的运营方仅凭随便注册一家公司、开发一款交易...