我的编程空间,编程开发者的网络收藏夹
学习永远不晚

node强缓存和协商缓存怎么实现

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

node强缓存和协商缓存怎么实现

这篇文章主要介绍了node强缓存和协商缓存怎么实现的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇node强缓存和协商缓存怎么实现文章都会有所收获,下面我们一起来看看吧。

    什么是浏览器缓存

    浏览器缓存(http 缓存) 是指浏览器在本地磁盘对用户最近请求过的文档进行存储,当访问者再次访问同一页面时,浏览器就可以直接从本地磁盘加载文档。

    优点

    减少了冗余的数据传输,节省带宽,减少服务器压力

    加快了客户端加载速度,提升用户体验。

    强缓存

    强缓存不会向服务器发送请求,而是直接从缓存中读取资源,强缓存可以通过设置两种 HTTP Header 实现:Expires 和 Cache-Control,这两个头部分别是HTTP1.0和HTTP1.1的实现。

    Expires

    Expires是HTTP1.0提出的一个表示资源过期时间的header,它描述的是一个绝对时间,由服务器返回。

    Expires 受限于本地时间,如果修改了本地时间,就会造成缓存失效。

    Cache-Control

    Cache-Control 出现于 HTTP/1.1,常见字段是max-age,单位是秒,很多web服务器都有默认配置,优先级高于Expires,表示的是相对时间。

    例如Cache-Control:max-age=3600 代表资源的有效期是 3600 秒。取的是响应头中的 Date,请求发送的时间,表示当前资源在 Date ~ Date +3600s 这段时间里都是有效的。Cache-Control 还拥有多个值:

    • no-cache 不直接使用缓存,也就是跳过强缓存。

    • no-store 禁止浏览器缓存数据,每次请求资源都会向服务器要完整的资源。

    • public 可以被所有用户缓存,包括终端用户和 CDN 等中间件代理服务器。

    • private 只允许终端用户的浏览器缓存,不允许其他中间代理服务器缓存。

    要注意的就是no-cache和no-store的区别,no-cache是跳过强缓存,还是会走协商缓存的步骤,而no-store是真正的完全不走缓存,所有资源都不会缓存在本地

    协商缓存

    当浏览器对某个资源的请求没有命中强缓存,就会发一个请求到服务器,验证协商缓存是否命中,如果协商缓存命中,请求响应返回的http状态为304并且会显示一个Not Modified的字符串。

    协商缓存用的是【Last-Modified,If-Modified-Since】和【ETag、If-None-Match】这两对Header来管理的。

    注意!!协商缓存需要配合强缓存使用,使用协商缓存需要先设置Cache-Control:no-cache或者pragma:no-cache来告诉浏览器不走强缓存

    Last-Modified、If-Modified-Since

    这两个Header是HTTP1.0版本提出来的,两个字段配合使用。

    Last-Modified 表示本地文件最后修改日期,浏览器会在请求头带上If-Modified-Since(上次返回的Last-Modified的值),服务器会将这个值与资源修改的时间匹配,如果时间不一致,服务器会返回新的资源,并且将 Last-Modified 值更新,作为响应头返回给浏览器。如果时间一致,表示资源没有更新,服务器返回 304 状态码,浏览器拿到响应状态码后从本地缓存中读取资源。

    但Last-Modified有几个问题。

    • 文件虽然被修改了,但最终的内容没有变化,这样文件修改时间还是会被更新

    • 有的文件修改频率在秒以内,这时候以秒粒度来记录就不够了

    • 有的服务器无法精确获取文件的最后修改时间。

    所以出现了ETAG。

    ETag、If-None-Match

    在HTTP1.1版本中,服务器通过 Etag 来设置响应头缓存标识。Etag 的值由服务端生成。在第一次请求时,服务器会将资源和 Etag 一并返回给浏览器,浏览器将两者缓存到本地缓存数据库。在第二次请求时,浏览器会将 Etag 信息放到 If-None-Match 请求头去访问服务器,服务器收到请求后,会将服务器中的文件标识与浏览器发来的标识进行对比,如果不相同,服务器返回更新的资源和新的 Etag ,如果相同,服务器返回 304 状态码,浏览器读取缓存。

    node强缓存和协商缓存怎么实现

    流程总结

    node强缓存和协商缓存怎么实现

    总结这几个字段:

    • Cache-Control —— 请求服务器之前

    • Expires —— 请求服务器之前

    • If-None-Match (Etag) —— 请求服务器

    • If-Modified-Since (Last-Modified) —— 请求服务器

    node实践

    本文用koa来做例子,因为koa是更轻量级的、更纯净的,本身并没有捆绑任何中间件,相比express自带了很多router、static等多种中间件函数,koa更适合本文来做示例。

    koa启动服务

    秉着学习和更容易理解的宗旨,不使用koa-static和koa-router中间件,用koa简易实现web服务器来验证之前的结论。

    创建项目
    # 创建并进入一个目录并新建index.js文件mkdir koa-cachecd koa-cachetouch index.js# 初始化项目git inityarn init# 将 koa 安装为本地依赖yarn add koa
    koa代码
    const Koa = require('koa')const app = new Koa()app.use(async (ctx) => {    ctx.body = 'hello koa'})app.listen(3000, () => {  console.log('starting at port 3000')})

    启动服务

    node index.js

    这样一个koa服务就起来了,访问localhost:3000可以就看到hello koa。

    为了方便调试,修改代码不用重新启动,推荐使用nodemon或者pm2启动服务。

    原生koa实现简易静态资源服务

    实现一个静态资源服务器关键点就是根据前端请求的地址来判断请求的资源类型,设置返回的Content-Type,让浏览器知道返回的内容类型,浏览器才能决定以什么形式,什么编码来读取返回的内容。

    定义资源类型列表

    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]}

    fs读取文件

    const parseStatic = (dir) => {  return new Promise((resolve) => {    resolve(fs.readFileSync(dir), 'binary')  })}

    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 {    ctx.set('Content-Type', parseMime(url))    ctx.body = await parseStatic(path.relative('/', url))  }})

    这样基本也就完成了一个简单的静态资源服务器。然后在根目录下新建一个html文件和static目录,并在static下放一些文件。这时候的目录应该是这样的:

    |-- koa-cache    |-- index.html    |-- index.js    |-- static        |-- css            |-- color.css            |-- ...        |-- image            |-- soldier.png            |-- ...        ...   ...

    这时候就可以通过localhost:3000/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>test cache</title>   <link rel="stylesheet" href="/static/css/index.css" rel="external nofollow"  /> </head> <body>   <div id="app">测试css文件</div>   <img class="lazy" data-src="/static/image/soldier.png" alt="" /> </body></html>

    css/color.css

    #app {  color: blue;}

    这时候打开localhost:3000,就能看到效果

    到这里基本的环境就都搭好了。接下来进入验证阶段。

    强缓存验证

    在没有任何配置之前,可以看下network:

    node强缓存和协商缓存怎么实现

    这时候无论是首次还是第几次,都会向服务器请求资源。

    注意!!!在开始实验之前要把network面板的Disable cache勾选去掉,这个选项表示禁用浏览器缓存,浏览器请求会带上Cache-Control: no-cache和Pragma: no-cache头部信息,这时候所有的请求都不会走缓存

    node强缓存和协商缓存怎么实现

    设置Expire

    修改index.js中的app.use代码段。

    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))    // 设置过期时间在30000毫秒,也就是30秒后    ctx.set('Expires', new Date(Date.now() + 30000))    ctx.body = await parseStatic(filePath)  }})

    用ctx.set(&lsquo;Expires&rsquo;, new Date(Date.now() + 30000)),设置过期时间为当期时间的30000毫秒,也就是30秒后(后面的设置头部信息都是这里修改)。

    再访问下localhost:3000,可以看到多了Expires这个Header。

    node强缓存和协商缓存怎么实现

    后面在30秒之内访问都可以看到network的Size,css文件显示的是disk cache,而image资源显示的是from memory cache。这时候浏览器是直接读的浏览器缓存,并没有请求服务器,可以尝试把css和图片文件改名称或者删除验证下,页面显示正常,说明之前的结论是没错的。

    node强缓存和协商缓存怎么实现

    Cache-Control

    ctx.set(&lsquo;Cache-Control&rsquo;, &lsquo;max-age=300&rsquo;)设置300秒有效期,验证方式同上。

    协商缓存验证

    Last-Modified,If-Modified-Since

    HTTP1.0协商缓存关键点就是根据客户端请求带的ifModifiedSince字段的时间和请求的资源对应的修改时间来判断资源是否有更新。

    首先设置Cache-Control: no-cache, 使客户端不走强缓存,再判断客户端请求是否有带ifModifiedSince字段,没有就设置Last-Modified字段,并返回资源文件。如果有就用fs.stat读取资源文件的修改时间,并进行对比,如果时间一样,则返回状态码304。

     ctx.set('Cache-Control', 'no-cache') const ifModifiedSince = ctx.request.header['if-modified-since'] const fileStat = await getFileStat(filePath) if (ifModifiedSince === fileStat.mtime.toGMTString()) {    ctx.status = 304 } else {    ctx.set('Last-Modified', fileStat.mtime.toGMTString())    ctx.body = await parseStatic(filePath) }

    etag、If-None-Match

    etag的关键点在于计算资源文件的唯一性,这里使用nodejs内置的crypto模块来计算文件的hash值,并用十六进制的字符串表示。cypto的用法可以看nodejs的官网
    。crpto不仅支持字符串的加密,还支持传入buffer加密,作为nodejs的内置模块,在这里用来计算文件的唯一标识再合适不过。

        ctx.set('Cache-Control', 'no-cache')    const fileBuffer = await parseStatic(filePath)    const ifNoneMatch = ctx.request.headers['if-none-match']    const hash = crypto.createHash('md5')    hash.update(fileBuffer)    const etag = `"${hash.digest('hex')}"`    if (ifNoneMatch === etag) {      ctx.status = 304    } else {      ctx.set('etag', etag)      ctx.body = fileBuffer    }

    效果如下图,第二次请求浏览器会带上If-None-Match,服务器计算文件的hash值再次比较,相同则返回304,不同再返回新的文件。而如果修改了文件,文件的hash值也就变了,这时候两个hash不匹配,服务器则返回新的文件并带上新文件的hash值作为etag。

    node强缓存和协商缓存怎么实现

    关于“node强缓存和协商缓存怎么实现”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“node强缓存和协商缓存怎么实现”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注编程网行业资讯频道。

    免责声明:

    ① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

    ② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

    node强缓存和协商缓存怎么实现

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档

    猜你喜欢

    node强缓存和协商缓存怎么实现

    这篇文章主要介绍了node强缓存和协商缓存怎么实现的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇node强缓存和协商缓存怎么实现文章都会有所收获,下面我们一起来看看吧。什么是浏览器缓存浏览器缓存(http 缓存
    2023-07-02

    js前端面试常见浏览器缓存强缓存及协商缓存的方法

    这篇文章主要介绍“js前端面试常见浏览器缓存强缓存及协商缓存的方法”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“js前端面试常见浏览器缓存强缓存及协商缓存的方法”文章能帮助大家解决问题。前言浏览器缓
    2023-07-02

    缓存是什么?用node怎么实现?

    浏览器缓存是前端优化的一个重要方向,通过缓存静态资源,可以减少页面的加载时间和减轻服务器负担,提高用户体验。本文将介绍浏览器缓存的基本原理和常见的缓存策略,并用 nodejs的 koa 框架下的代码实现。
    2023-05-14

    用node如何实现缓存

    本文小编为大家详细介绍“用node如何实现缓存”,内容详细,步骤清晰,细节处理妥当,希望这篇“用node如何实现缓存”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。缓存原理浏览器缓存的基本原理是将静态资源(如 CS
    2023-07-05

    Redis的缓存预热和缓存降级怎么实施

    缓存预热和缓存降级是在使用Redis作为缓存时常用的两种策略,可以提高系统性能和稳定性。缓存预热:缓存预热是指在系统启动或服务升级时,提前将一部分热门数据加载到缓存中,以提高系统的响应速度和性能。实施缓存预热可以通过以下几种方式:定时任务
    Redis的缓存预热和缓存降级怎么实施
    2024-05-07

    php怎么实现redis缓存

    PHP中的Redis缓存在PHP中使用Redis缓存可显著提升性能。本指南介绍如何使用Predis客户端库一步步连接到Redis服务器、设置缓存值、获取缓存值、删除缓存值、设置缓存过期时间、实现缓存锁定,以及利用Redis的哈希表、发布/订阅功能。通过遵循本指南,开发人员可以轻松地将Redis集成到他们的PHP应用程序中,从而提高性能和可伸缩性。
    php怎么实现redis缓存
    2024-04-10

    golang cache缓存怎么实现

    在Go语言中,实现缓存可以使用以下两种方式:使用sync.Map实现缓存:sync.Map是Go语言提供的并发安全的map,可以用于实现缓存。可以使用sync.Map的Load和Store方法来获取和存储缓存数据。package maini
    golang cache缓存怎么实现
    2024-02-29

    怎么实现SpringBoot缓存系统

    这篇文章主要介绍“怎么实现SpringBoot缓存系统”,在日常操作中,相信很多人在怎么实现SpringBoot缓存系统问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么实现SpringBoot缓存系统”的疑
    2023-06-16

    MybatisPlus二级缓存怎么实现

    这篇文章主要介绍了MybatisPlus二级缓存怎么实现的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇MybatisPlus二级缓存怎么实现文章都会有所收获,下面我们一起来看看吧。一、序言本文承接[Mybati
    2023-06-29

    Vue页面缓存怎么实现

    这篇文章主要介绍“Vue页面缓存怎么实现”,在日常操作中,相信很多人在Vue页面缓存怎么实现问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Vue页面缓存怎么实现”的疑惑有所帮助!接下来,请跟着小编一起来学习吧
    2023-07-06

    thinkphp怎么实现清除缓存

    本篇内容介绍了“thinkphp怎么实现清除缓存”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!thinkphp实现清除缓存dedecms有清
    2023-06-25

    java二级缓存怎么实现

    Java二级缓存的实现可以通过使用第三方缓存库或自定义缓存类来完成。1. 使用第三方缓存库:常见的第三方缓存库有Ehcache、Redis等。可以通过引入对应的库,配置缓存的参数,然后在代码中使用相应的API进行缓存的操作。例如,使用Ehc
    2023-08-20

    Redis的缓存雪崩和缓存击穿怎么避免

    缓存雪崩是指在某个时间点,大量缓存同时失效,导致大量请求直接访问数据库,造成数据库压力过大的情况。缓存击穿是指某个热点数据突然失效,导致大量请求同时访问数据库,也会造成数据库压力过大。为了避免缓存雪崩和缓存击穿,可以采取以下措施:设置合理
    Redis的缓存雪崩和缓存击穿怎么避免
    2024-05-07

    怎么使用Spring提供的不同缓存注解实现缓存

    这篇文章主要介绍了怎么使用Spring提供的不同缓存注解实现缓存的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇怎么使用Spring提供的不同缓存注解实现缓存文章都会有所收获,下面我们一起来看看吧。前言缓存可以通
    2023-07-06

    编程热搜

    • Python 学习之路 - Python
      一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
      Python 学习之路 - Python
    • chatgpt的中文全称是什么
      chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
      chatgpt的中文全称是什么
    • C/C++中extern函数使用详解
    • C/C++可变参数的使用
      可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
      C/C++可变参数的使用
    • css样式文件该放在哪里
    • php中数组下标必须是连续的吗
    • Python 3 教程
      Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
      Python 3 教程
    • Python pip包管理
      一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
      Python pip包管理
    • ubuntu如何重新编译内核
    • 改善Java代码之慎用java动态编译

    目录