本文由 简悦 SimpRead 转码, 原文地址 mp.weixin.qq.com
大厂技术 高级前端 Node进阶
点击上方 程序员成长指北,关注公众号
回复1,加入高级Node交流群面试中总被问到强缓存 & 协商缓存面试题,也看过一些面经 也知道强缓存直接用缓存,协商缓存会询问服务器资源有没有更新这些叭叭叭的,但对于具体怎么实现却是一无所知,今天就通过实操把强缓存 & 协商缓存彻底搞懂。(实操环节在下面)
为什么要使用缓存
Web 应用中说的缓存一般都是对网站中引用的静态资源进行缓存,比如 js/css / 图片 / 视频这些资源,使用缓存可以减少网络延迟和带宽消耗,对于咱们前端开发者来说最重要的是可以大幅度的提高网页打开速度,当老板访问你做的公司官网直接秒开,老板一高兴不得多给你多发 200 块奖金。
强缓存和协商缓存的区别
废话不多说,6 张截图带你了解强缓存和协商缓存的差异:
不使用缓存:
图 1:
no-cache-request.png
图 2:
no-cache-header.png
图 2 是随便一个 js 文件的请求详情,可以看出虽然此时没有开启缓存,但是 nginx 作为 Web 服务器,会自动返回Etag和Last-Modified响应头,这两个响应头跟缓存息息相关,后面要考的。
强缓存
强缓存通过让浏览器直接从缓存中获取资源,而不与服务器进行任何通信,极大地减少了网络请求。
图 3:
image.png
图 4:
force-cache-header.png
图 3 可以看到Size列显示的不再是文件大小,而是memory cache或disk cache,这就是命中了强缓存的标志,并且现在的 Load 时长只有 65ms,相比于图 1 的 4.7s 提升了多少倍。
通过图 4 可以看到,在使用了强缓存后响应头中会多一个Cache-Control: max-age=60,聪明的同学已经明白了,这代表着这个资源的缓存有效期为 60 秒。
看到这你可能会想:过了有效期后会重新加载资源吗?
答案就是不一定,这里就用到了协商缓存。
协商缓存
简单来讲协商缓存就是通过请求头中的 If-Modified-Since 和 If-None-Match 来判断资源有没有改动,如果有改动,就更新缓存,如果没有改动,就使用缓存。
这个过程会发生请求,但是如果命中缓存,则减少了资源的传输过程
If-Modified-Since:
这个头部字段的值是该资源上次修改的时间(即响应头中的 Last-Modified)。
服务器会根据资源的最后修改时间来判断资源是否发生了变化。如果资源自上次修改时间以来没有修改过,服务器会返回 304 Not Modified 状态码。
If-None-Match
这个头部字段的值基于资源的文件大小和最后修改时间等信息来生成,会在上次请求资源时返回(即响应头中的 ETag)。
服务器会根据 ETag 来判断资源是否发生了变化。如果 ETag 没有变化,服务器会返回 304 Not Modified 状态码。
优先级
如果请求中同时包含 If-Modified-Since 和 If-None-Match,服务器会优先使用 If-None-Match 进行判断。
只有在 If-None-Match 不存在或服务器不支持 ETag 的情况下,才会使用 If-Modified-Since 进行判断。
图 5:
image.png
图 6:
over-expires-request-header.png
从图 5 能看出,资源 status 都是 304,这就是协商缓存的标志
再看图 6 请求头中也是包含了 If-Modified-Since 和 If-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」即可。
“分享、点赞、在看” 支持一波👍