当前位置:网站首页> 实践示例理解js强缓存协商缓存
实践示例理解js强缓存协商缓存
2022-07-04 18:39:00 【1024问】
背景
前置准备
准备
启动页面
HTTP缓存种类
强缓存
expires
cache-control
协商缓存
Last-Modified,If-Modified-Since
Etag,If-None-Match
总结
背景无论是开发中或者是面试中,HTTP缓存都是非常重要的,这体现在了两个方面:
开发中:合理利用HTTP缓存可以提高前端页面的性能
面试中:HTTP缓存是面试中的高频问点
所以本篇文章,我不讲废话,我就通过Nodejs的简单实践,给大家讲最通俗易懂的HTTP缓存,大家通过这篇文章一定能了解掌握它!!!
前置准备准备创建文件夹cache-study,并准备环境
npm init
安装Koa、nodemon
npm i koa -Dnpm i nodemon -g
创建index.js、index.html、static文件夹
index.html
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <link rel="stylesheet" href="./static/css/index.css" rel="external nofollow" ></head><body> <div class="box"> </div></body></html>
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缓存常见的有两类:
强缓存:可以由这两个字段其中一个决定
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跟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跟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://www.jb51.net/article/254078.htm
以上就是实践示例理解js强缓存协商缓存的详细内容,更多关于js强缓存协商缓存的资料请关注软件开发网其它相关文章!
边栏推荐
- Kotlin classes and objects
- 【历史上的今天】7 月 4 日:第一本电子书问世;磁条卡的发明者出生;掌上电脑先驱诞生
- Creation of JVM family objects
- What financial products can you buy with a deposit of 100000 yuan?
- Niuke Xiaobai monthly race 7 I new Microsoft Office Word document
- Abc229 summary (connected component count of the longest continuous character graph in the interval)
- Crystal optoelectronics: ar-hud products of Chang'an dark blue sl03 are supplied by the company
- B2B mall system development of electronic components: an example of enabling enterprises to build standardized purchase, sale and inventory processes
- 水晶光电:长安深蓝SL03的AR-HUD产品由公司供应
- 2022 Health Exhibition, Beijing Health Expo, China Health Exhibition, great health exhibition November 13
猜你喜欢
c# . Net MVC uses Baidu ueditor rich text box to upload files (pictures, videos, etc.)
Huawei Nova 10 series supports the application security detection function to build a strong mobile security firewall
记一次 .NET 某工控数据采集平台 线程数 爆高分析
TCP两次挥手,你见过吗?那四次握手呢?
C# 使用StopWatch测量程序运行时间
Free soldier
Niuke Xiaobai month race 7 who is the divine Archer
Decryption function calculates "task state and lifecycle management" of asynchronous task capability
Optimization cases of complex factor calculation: deep imbalance, buying and selling pressure index, volatility calculation
The explain statement in MySQL queries whether SQL is indexed, and several types in extra collate and summarize
随机推荐
What financial products can you buy with a deposit of 100000 yuan?
Key rendering paths for performance optimization
2022 version of stronger jsonpath compatibility and performance test (snack3, fastjson2, jayway.jsonpath)
Swagger突然发癫
HDU 1372 & POJ 2243 Knight moves (breadth first search)
水晶光电:长安深蓝SL03的AR-HUD产品由公司供应
Prometheus installation
上线首月,这家露营地游客好评率高达99.9%!他是怎么做到的?
kotlin 基本使用
[graduation season] green ant new fermented grains wine, red mud small stove. If it snows late, can you drink a cup?
Data set division
输入的查询SQL语句,是如何执行的?
repeat_ P1002 [NOIP2002 popularization group] cross the river pawn_ dp
2022 Health Exhibition, health exhibition, Beijing Great Health Exhibition and health industry exhibition were held in November
The company needs to be monitored. How do ZABBIX and Prometheus choose? That's the right choice!
Optimize if code with policy mode [policy mode]
Write it down once Net analysis of thread burst height of an industrial control data acquisition platform
c# .net mvc 使用百度Ueditor富文本框上传文件(图片,视频等)
Application practice | Shuhai supply chain construction of data center based on Apache Doris
Double colon function operator and namespace explanation