这里说的不仅仅是我们常见的强缓存
和协商缓存
,还有浏览器自带的缓存机制
,即使我们什么也没有配置也自带的隐式缓存(启发式缓存
);
如果没有缓存机制,刷新页面的时候,不管是以什么样的形式刷新(前进/后退/普通刷新/强制刷新),那么每次浏览器都会去请求服务器的资源,想想是有多么的可怕,这样会大大的增加服务器的压力和带宽。
所以浏览器为了解决这个问题,当第一个请求资源完成后,根据相应的缓存机制,将一些静态资源存储在本地磁盘当中,这样下次请求资源的时候,浏览器直接从本地缓存中读取文件,不需要再次发送请求。
这个如图弹框如何被打开的呢,打开控制台之后再右键刷新按钮即可。
方法:地址栏回车、页面链接跳转、打开新窗口/标签页、history前进后退,点击刷新按钮、页面右键重新加载、F5、ctrl+R
执行上面这些刷新操作,如果缓存不过期,会使用缓存。
这样浏览器可以避免重新下载JavaScript文件,图像,文本文件等,直接读取缓存信息。
方法:点击硬性重新加载、Ctrl+F5、Ctrl+Shift+R、
执行上面这些刷新操作,清除了关键位置的缓存;所有的资源,都会跳过缓存判断,发起真实的请求,从服务端拿资源。但本地的缓存资源(如disk里的缓存)并没有删除。这种方式会在Request Header里添加Cache-Control:no-cache和Pragma: no-cache
,也是浏览器自己的行为。
方法:点击左上角的清空缓存并硬性重新加载
这种方式,相当于先删除缓存(如 disk磁盘 和 memory内存 里的缓存),再执行硬性重新加载。
如下图所示:
Size
栏:disk cache 代表走磁盘缓存,memory cache 走内存缓存;Cache-Control
栏:查看缓存策略,可以看到配置文件setting.js没有配置任何缓存策略此时没有配置任何缓存策略,但还是走了本地缓存,这就是下面要说的浏览器的默认缓存(启发式缓存)。
一开始是没有 Cache-Control
这一栏的,需要手动设置一下,在头部右键勾选上 Cache-Control 即可。
下图的资源则配置了强缓存和协商缓存
缓存的默认行为(即对于没有 Cache-Control 的响应)不是简单的“不缓存”,而是根据所谓的“启发式缓存
”进行隐式缓存。
HTTP 旨在尽可能多地缓存,因此即使没有给出 Cache-Control,如果满足某些条件,响应也会被存储和重用。这称为启发式缓存
。
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1024
Date: Tue, 22 Feb 2022 22:22:22 GMT
Last-Modified: Tue, 22 Feb 2021 22:22:22 GMT
<!doctype html>
…
22:22:22 GMT:北京时间比浏览器时间晚8小时
公式为:( Date - Last-Modified ) * 0.1
Date
:当前请求的时间Last-Modified
:服务器中资源最后被修改的日期MDN:试探性地知道,整整一年没有更新的内容在那之后的一段时间内不会更新。因此,客户端存储此响应(尽管缺少 max-age)并重用它一段时间。复用多长时间取决于实现,但规范建议存储后大约 10%(在本例中为 0.1 年)的时间。
也就是说,如果十天没有更新的资源,会缓存一天的时间,在这段时间内浏览器请求走的都是本地缓存,超出这个时间则向服务器请求资源。
启发式缓存是在 Cache-Control 被广泛采用之前出现的一种解决方法,基本上所有响应都应明确指定 Cache-Control 标头。
这里会比较绕,这个默认缓存的时间到底会缓存多久?是如何进行判断的?
我们查看一个配置文件的缓存,是没有配置缓存策略的,则默认启发式缓存;
再看下该文件响应头中的 Date
和 Last-Modified
信息,这里的这两个时间是决定下次刷新页面之后,是请求服务器还是走本地缓存的关键因素,注意是下一次请求!
此时当前这一次请求的响应头 (Date - Last-Modified) * 0.1 是决定该文件缓存时间的长短,也就是 (2023-04-13 - 2023-03-09) 等于35天(具体时间时分秒先不计算),再乘以0.1,则当前文件则会缓存大约3.5天的时间,用户下次请求这个文件的时候,在3.5天之内请求则直接走本地缓存获取,超过3.5天去请求当前文件,则会去请求服务器的资源,不再走缓存!
在 Last-Modified (文件最后修改时间)不变的前提下,随着时间的推移,该资源缓存的时间会越来越长~
站在开发者的角度来解析这个问题,当我们自己在做测试启发式缓存的时候,容易出现错乱,就是感受不到启发式缓存的效果,不知道你们有没有遇到过。只要掌握上面的计算方法,一步步拆分,就可以轻松的识别和判断启发式缓存。
再来看,还是刚才那个文件,在服务器修改了文件的内容,Date 和 Last-Modified 只相差27秒,也就说当前文件只会缓存2.7秒。因为我们刚刚修改了服务器资源内容,需要强制刷新获取的最新文件,是发请求到服务器的,没有走本地缓存,所以这次是看不到效果的,正常是不能用强制刷新的;想要看到效果,在做测试的时候肯定会再次去修改服务器中该文件的内容,然后用普通刷新去看当前文件到底是不是走启发式缓存。
当再次修改服务器资源后刷新页面,如上图所示,发现 config.js 还是请求的服务器资源!没有走缓存!如果走缓存的话,Size栏是disk cache 或者 memory cache,这是为什么呢?因为之前上次请求资源的Date 和 Last-Modified决定下次请求是否走缓存,上次请求资源只缓存了2.7s,我们在服务器改了内容再返回页面去刷新查看结果的这个过程超过了2.7s就会重新请求服务器资源!
所以说,我们做测试的时候一定注意尽可能的把Date 和 Last-Modified时间拉大一点,才能看出效果。
此时,我们把时间拉的稍微大一点,再去修改服务器中的资源,(49 - 33) * 0.1 大约会缓存一分半时间;
在这一分半时间内,去服务器修改资源之后再去刷新页面,发现此时此刻 config.js 走的就是缓存了,我们服务器虽然修改了 config.js 里面的内容,但是在这个缓存的时间内仍然获取不到最新的内容!所以说系统的配置文件要配置协商缓存。
在HTTP/1.1中,Cache-Control
是最重要的规则,主要用于控制网页缓存,主要取值为:
这里主要解读下max-age=0,no-cache,max-age=10086,no-store这几项:
Cache-Control : no-cache
no-cache
:表示协商缓存,每次请求还是会和服务器去比对资源有没有修改(也就是拿ETag或者Last-Modified进行比较),如果资源没改变,则直接返回304状态码(Not Modified),说明无需再次传输请求的内容,也就是说可以使用缓存的内容;如果资源改变,则返回200状态码,并且返回新的资源;
Cache-Control : max-age=0,must-revalidate
max-age=0 和 must-revalidate
的组合与 no-cache 具有相同的含义。但是这是为了兼容处理解决HTTP/1.1 之前的许多实现无法处理 no-cache 的情况,但是现在基本都是HTTP/1.1,所以没有理由再用这种方法了,转而直接用 no-cache 则更好!
为确保默认情况下始终传输最新版本的资源,通常的做法是让默认的 Cache-Control 值包含 no-cache
另外,如果服务实现了 cookie 或其他登录方式,并且内容是为每个用户个性化的,那么也必须提供 private,以防止与其他用户共享:
Cache-Control: no-cache, private
Cache-Control : max-age=10086
max-age=10086
:表示强缓存,服务器直接告诉浏览器10086秒不要来烦我,你直接从本地缓存获取资源吧;如果是硬性重新加载,浏览器则表示:我就要向你服务器重新获取资源,你能咋滴吧,不还得乖乖返回给我(狗头);
Cache-Control : no-store
no-store
:表示不缓存,浏览器自带的启发式缓存都不生效了,慎用!
其实这两者差别不大,区别就在于 Expires
是http1.0
的产物,Cache-Control
是http1.1
的产物,两者同时存在的话,Cache-Control优先级高于Expires
;在某些不支持HTTP1.1的环境下,Expires就会发挥用处。所以Expires其实是过时的产物,现阶段它的存在只是一种兼容性的写法。
启发式缓存
的缓存时间不是可控的,是根据用户请求的 Date 和 Last-Modified决定缓存的时间;强缓存
是只要在设置的时间范围内,缓存一直都生效,除非资源变动。你可能认为添加 no-store
只是不进行强缓存和协商缓存了。
但是,连浏览器自带的启发式缓存策略都没了,所以不建议随意授予 no-store,因为你失去了 HTTP 和浏览器所拥有的许多优势,包括浏览器的后退/前进缓存。
因此,要获得 Web 平台的全部功能集的优势,最好不要轻易设置 no-store。
永远不会改变的内容应该被赋予一个较长的 max-age
;
但是,当用户重新加载时,即使服务器知道内容是不可变的,也会发送重新验证请求。
为了防止这种情况,immutable
指令可用于明确指示不需要重新验证,因为内容永远不会改变。
Cache-Control: max-age=10086, immutable
缓存破坏
是一种通过在内容更改时更改 URL 来使响应在很长一段时间内可缓存的技术。该技术可以应用于所有子资源,例如图像。简单来说就是index.html里的所有子资源如js、css、图片等,在部署时,通过url的变化,使重新获取新的资源。
当向服务器部署一个前端资源包,虽然把包放到了服务器中,浏览器是如何立马就能知道这是新的资源,从而去获取这些新的资源,而不是去获取浏览器缓存的资源呢?
如何破坏缓存:
这里重点说一下Hash值类型,Vue的生产环境打包采用的也是这种方式;在静态资源文件末尾加上Hash值,保证当前打的包和服务器之前部署的文件区分开来,避免文件名一致,而导致虽然部署成功了,浏览器请求的还是缓存的资源!
缓存是根据它们的 URL 来区分资源,因此如果在更新资源时 URL 发生变化,缓存将不会再次被重用。
这些打包好的js、css、img等静态资源最终会在index.html中引用,在访问一个网站的时候,首先会请求index.html,再去请求 index.html 里面的引用,此时html中引用的 js 等文件,和服务器中 html 引用的 js 等文件已经不是同一个文件了,因为文件名变了(加了Hash值),所以不会走本地缓存。
如果部署了资源,但是刷新页面没有获取到最新的版本内容,我们第一反应是清空浏览器缓存,但是我们不是用户,也不能要求用户每次去清空缓存,户刷新页面大部分是正常重新加载里面的一些方式方法,所以遇到这种问题我们的解决方法如下:
使用 Cache-Control: no-cache
协商缓存,使浏览器每次都请求服务器,然后配合 ETag 或者 Last-Modified 来验证资源是否有效,来保证获取的是最新的文件;
拿setting.js举例:此时浏览器获取的内容为
此时正好赶上一个需求,需要把页面所有内容设置为灰色,因为事先在配置文件里面配置了,所以此时只需要在setting.js中把 gray 改为 true 即可,如下图所示,这个文件是没有设置缓存策略的,走的默认缓存,获取的是内存中【memory cache】的缓存;
现在修改一下数据库的该文件信息,进行保存
再回到浏览器执行用户常用的正常重新加载式刷新页面,发现页面并没有任何变化,查看该文件信息,发现还是获取的之前信息,并没有重新获取服务器修改过的资源信息!因为没有配置相应的缓存策略,用户使用起来就会有问题了,获取不到最新的内容。
这里也涉及到启发式缓存时间的问题,如果在服务器多次改变该文件内容,并且页面刷新频繁(自己测试的时候会频繁刷新,注意 Response Header 中的 Date 和 Last-Modified
时间的间隔,如果间隔时间很短,短到只有几秒钟,那么你修改配置文件之后,此时再刷新页面就会去请求服务器资源,而不是走缓存了;但是真实用户的 Date 和 Last-Modified 时间间隔不会这么短,默认缓存时间较长),缓存时间就会缩的非常短,让你产生没有配置协商缓存的话,页面也会同步更新,但是这样是有问题的!
所以对于这些文件要配置协商缓存,保证每次获取的都是最新的文件!
使用 Cache-Control
配置一个很大的 max-age=31536000
(一年);
当重新打的包是带有Hash值的,所以不怕这个强缓存,管它之前缓存的是一年、两年还是十年,当重新部署到服务器的时候,浏览器就得加载最新部署的资源。
使用Nginx
设置缓存策略
为什么说 index.html 和 setting.js 要设置协商缓存呢?因为他们的文件名是不可能带hash的,所以要设置协商缓存每次去验证资源是否有效。
在 nginx.conf
中配置以下内容:
server {
# html设置成协商缓存或者不缓存
location ~* \.(html)$ {
# 关闭访问日志
access_log off;
# 进行协商缓存 保证每次调取最新的数据
add_header Cache-Control no-cache;
}
# 特定文件设置强缓存
location ~* \.(css|js|png|jpg|jpeg|gif|gz|svg|mp4|ogg|ogv|webm|htc|xml|woff)$ {
add_header Cache-Control max-age=360000; # 默认4天
#add_header Cache-Control no-store; # 不缓存 但是不推荐 浏览器自带的优化功能用不了了
#add_header Cache-Control no-cache; # 协商缓存 保证每次调取最新的数据
# 系统配置文件setting.js,进行协商缓存 保证每次调取最新的数据
if ($request_filename ~* \.*setting.(js)$) {
add_header Cache-Control no-cache;
}
}
}
设置好后,重启nginx服务,强制刷新再普通刷新页面,会发现资源已经根据 nginx 配置了对应的缓存策略,Size栏也能看到是获取的内存中的缓存。
本文由微信公众号三分钟学前端原创,哈喽比特收录。
文章来源:https://mp.weixin.qq.com/s/oR_S1P22TBfMuUPaXjvcnQ
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。