大厂技术  高级前端  Node进阶点击上方 程序员成长指北,关注公众号
回复1,加入高级Node交流群

面试中总被问到强缓存&协商缓存面试题,也看过一些面经 也知道强缓存直接用缓存,协商缓存会询问服务器资源有没有更新这些叭叭叭的,但对于具体怎么实现却是一无所知,今天就通过实操把强缓存&协商缓存彻底搞懂。(实操环节在下面)

为什么要使用缓存

Web应用中说的缓存一般都是对网站中引用的静态资源进行缓存,比如js/css/图片/视频这些资源,使用缓存可以减少网络延迟和带宽消耗,对于咱们前端开发者来说最重要的是可以大幅度的提高网页打开速度,当老板访问你做的公司官网直接秒开,老板一高兴不得多给你多发200块奖金。

强缓存和协商缓存的区别

废话不多说,6张截图带你了解强缓存和协商缓存的差异:

不使用缓存:

图1:

93ddcad1453758f95ac2c5c880853e88.jpeg

no-cache-request.png

图2:

0cc61859be093179cbbc3cb3b8cf4549.jpeg

no-cache-header.png

图2是随便一个js文件的请求详情,可以看出虽然此时没有开启缓存,但是nginx作为Web服务器,会自动返回EtagLast-Modified响应头,这两个响应头跟缓存息息相关,后面要考的。

强缓存

强缓存通过让浏览器直接从缓存中获取资源,而不与服务器进行任何通信,极大地减少了网络请求。

图3:

55e1d58caf8353b9ac641b278b7c1b10.jpeg

image.png

图4:

8cb64da4b4206a32409d5d003571b2fe.jpeg

force-cache-header.png

图3可以看到Size列显示的不再是文件大小,而是memory cachedisk cache,这就是命中了强缓存的标志,并且现在的Load时长只有65ms,相比于图14.7s提升了多少倍。

通过图4可以看到,在使用了强缓存后响应头中会多一个Cache-Control: max-age=60,聪明的同学已经明白了,这代表着这个资源的缓存有效期为60秒。

看到这你可能会想:过了有效期后会重新加载资源吗?

答案就是不一定,这里就用到了协商缓存。

协商缓存

简单来讲协商缓存就是通过请求头中的 If-Modified-Since 和 If-None-Match 来判断资源有没有改动,如果有改动,就更新缓存,如果没有改动,就使用缓存。

这个过程会发生请求,但是如果命中缓存,则减少了资源的传输过程

  1. If-Modified-Since:

    1. 这个头部字段的值是该资源上次修改的时间(即响应头中的 Last-Modified)。

    2. 服务器会根据资源的最后修改时间来判断资源是否发生了变化。如果资源自上次修改时间以来没有修改过,服务器会返回 304 Not Modified 状态码。

  2. If-None-Match

    1. 这个头部字段的值基于资源的文件大小和最后修改时间等信息来生成,会在上次请求资源时返回(即响应头中的 ETag)。

    2. 服务器会根据 ETag 来判断资源是否发生了变化。如果 ETag 没有变化,服务器会返回 304 Not Modified 状态码。

优先级

  • 如果请求中同时包含 If-Modified-Since 和 If-None-Match,服务器会优先使用 If-None-Match 进行判断。

  • 只有在 If-None-Match 不存在或服务器不支持 ETag 的情况下,才会使用 If-Modified-Since 进行判断。

图5:

6f0b5b2a36d543fc9a68831b2215a92c.jpeg

image.png

图6:

c9a23997a55c14d9d3c521419cd90512.jpeg

over-expires-request-header.png

图5能看出,资源status都是304,这就是协商缓存的标志

再看图6请求头中也是包含了 If-Modified-SinceIf-None-Match的,两者的作用上面已经说过了。

实操环节

实操环节就很简单了,目前市面上一般都是nginx作为Web服务器的,所以咱们只需要修改nginx配置就可以了(大家在公司应该都配置过nginx吧)。

混合策略

同时使用强缓存和协商缓存,也是最好用的策略。

server {
    ... # 一些其他配置
    # 针对js、css和图片实行混合缓存策略
    location ~* .(js|css|png|jpg|jpeg|gif|ico|svg|webp)$ {
        # expires 主要是为了兼容 nginx 版本低于 1.2 的情况,如果版本高于1.2不用写
        expires 1m;
        add_header Cache-Control "public,max-age=60";
    }
    ... # 一些其他配置
}

混合缓存的工作流程:

一、初次请求&强缓存生效:

当你第一次请求资源时,服务器返回响应头,其中包含 Cache-Control: public, max-age=60。浏览器会根据这个指令将资源缓存起来,并标记为 60 秒内有效(强缓存)。

在这 60 秒内,每次请求该资源时,浏览器直接从缓存(memory cache 或 disk cache)中读取资源,而不会与服务器通信。

二、强缓存过期后:

60 秒过期后,浏览器不再信任缓存中的资源新鲜度。因此,下一次请求时,它会发送 If-Modified-Since 或 If-None-Match 请求头,询问服务器资源是否更新。

如果服务器发现资源未更新,则返回 304 Not Modified 响应。此时,浏览器会继续使用本地缓存中的资源,但会更新其过期时间,再次开始新一轮的 max-age=60 的计时。

三、协商缓存成功后的强缓存:

在接收到 304 响应后,浏览器会重置资源的过期时间(比如再延续 60 秒)。在这个新的 60 秒周期内,浏览器再次启用强缓存,即直接从缓存中读取资源,而不与服务器通信。

因此,在缓存没有过期的情况下(即在 max-age 期限内),浏览器始终使用强缓存,只有在缓存过期时,才会触发协商缓存。

总结

  • 强缓存优先: 浏览器在 max-age 期限内,优先使用强缓存,即从 memory cache 或 disk cache 中直接读取资源。

  • 缓存过期后进行协商: 当强缓存过期后,浏览器会向服务器发送请求头(如 If-Modified-Since)进行协商缓存,判断资源是否更新。

  • 协商缓存后延续强缓存: 如果协商缓存返回 304 Not Modified,浏览器会继续使用缓存中的资源,并重置过期时间。

始终使用协商缓存

通过设置 Cache-Control "no-cache" 响应头, 告诉浏览器在每次请求时都必须向服务器发送请求,以验证缓存内容是否过期或需要更新。浏览器会发送 If-Modified-Since 或 If-None-Match 请求头,服务器通过这些头信息决定是否返回 304 Not Modified。

server {
    ... # 一些其他配置
    location ~* .(js|css|png|jpg|jpeg|gif|ico|svg|webp)$ {
        add_header Cache-Control "no-cache";
    }
    ... # 一些其他配置
}

好了,自己起个web服务器去实操一下加深下印象吧

 本文转载于稀土掘金技术社区,作者:熬夜佩奇

 原文链接:https://juejin.cn/post/7407599381396422691

Node 社群



我组建了一个氛围特别好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你对Node.js学习感兴趣的话(后续有计划也可以),我们可以一起进行Node.js相关的交流、学习、共建。下方加 考拉 好友回复「Node」即可。

   “分享、点赞、在看” 支持一波👍
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐