前端缓存

前端缓存分为浏览器缓存和http缓存,浏览器缓存例如web Storage,cookie等,比较简单这里一笔带过。复杂的是http缓存,分为强缓存与协商缓存两种缓存策略

当然第一次进入一个网站没有缓存的概念,但是根据第一次返回的响应字段,可以得到对应的缓存策略,得益于缓存策略,第二次乃至以后进入网站速度大大提升。

强缓存

对应着这两个字段:HTTP/1.0时期,使用的是Expires ,而HTTP/1.1使用的是Cache-Control

Expires :服务端会返回缓存的过期时间点,超过这个时间点缓存失效。但是服务端与浏览器的时间可能不一致,会产生问题,所以被Cache-Control取代

Cache-Control:不是返回时间点而是持续时间

js 复制代码
Cache-Control:max-age=1000 // (单位是秒)

其下并不只有这一个属性,还有一些其他属性

no-cache:跳过强缓存,走协商缓存

no-store:强,协商缓存都没有

private:用户浏览器会缓存,中间负责转发的代理服务器不能缓存

public:代理服务器能缓存

s-maxage:代理服务器缓存时间

ExpiresCache-Control 同时存在的时候,Cache-Control优先级高

如果第二次进入到这个页面,执行缓存策略,第一步就是先判断强缓存,也就是 浏览器 根据返回的强缓存对应字段,判断缓存是否过期,如果没有过期,直接取缓存,不需要再进行协商缓存。

需要补充的是强缓存不需要发送http请求,虽然返回状态码还是200。另外这里的来源是内存/磁盘,并且只要是从内存/磁盘获取的就是走了强缓存。

协商缓存

协商 的字面意思上可以看出至少是需要两个人才能协商,也就是这里浏览器还要询问远程服务器缓存是否过期,也有两个字段

Last-Modified :服务器把这个字段返回,下一次浏览器发送http,会在请求头将他带上,只不过字段名改成了If-Modified-Since,接着服务器判断这个时间是否过期,如果返回304代表未过期,否则返回新资源。

ETag服务器根据文件内容生成的唯一标识 。服务器把这个字段返回,下一次浏览器发送http,会在请求头将他带上,字段名改成了If-None-Match ,服务器接着会跟服务器上该资源的ETag进行比对,如果返回304代表未过期,否则返回新资源。

接着上面的例子如果强缓存判断过期了,就会进入协商缓存,此时会发送http请求,请求头上会加上If-Modified-SinceIf-None-Match ,他们的值就是第一次返回的响应标头中的Last-ModifiedIf-Modified-Since。如果返回304代表缓存没过期,否则返回200,服务器返回最新资源。、

总结

来源于内存/磁盘都是强缓存,状态码返回304都是协商缓存,强缓存由浏览器控制,协商缓存由远程服务器控制。

场景

前端:项目已经部署了

测试:还是老样子啊,刷新也没用

前端:强制刷新一下

测试:哦,可以了

以前一直很疑惑这两种刷新有啥区别,跟这里的强缓存,协商缓存又有啥关系。

先通过nginx设置一下服务器缓存策略(强+协商缓存)

打开控制台,右键刷新图标出现三种刷新方式

  1. 正常重新加载,这里设置了强缓存1000s,可以看到来源都是强缓存,也就是说正常走缓存策略,缓存没过期接着用。

2. 硬性重新加载,使用硬性重新加载后资源的 请求标头 都被加上了 cache-control: no-cache 和 pragma: no-cache, pragma 则是为了兼容 HTTP/1.0。并且请求头上没有协商缓存对应的字段。也就是不走强缓存也不走协商缓存,服务器返回最新资源

需要注意的是这里的cache-control是在请求标头里,正常应该存在服务器的响应标头里
请求头里的Cache-Control影响的是当前这一次请求,响应头里的Cache-Control是告诉浏览器这样存储,下次依照这样来。影响的是下一次请求。

  1. 清除缓存并硬性重新加载:先去缓存再硬性重新加载

还有一种资源"始终"命中 memory cache,就是 base64 图片

但是使用硬性加载似乎不是所有资源都不走缓存,可以看到只有第一个是重新请求了,其他都走了强缓存(默认缓存策略)。

可能是html里直接引用的有关,这两个文件发现都是没有走缓存,而其他文件都是正常走缓存策略。

默认缓存策略

现在把nginx里设置的缓存策略都取消,看看 默认缓存策略

可以看到响应头里 没有强缓存 的字段,但是却 有协商缓存 的字段

  1. 正常重新加载:很奇怪走了强缓存,但是响应头没有强缓存的字段

其实浏览器还存在一个 启发式缓存 的东西,启发式缓存是浏览器缓存的默认行为(即对于没有 Cache-Control 的响应)不是简单的"不缓存",而是根据所谓的"启发式缓存"进行隐式缓存。

HTTP 旨在尽可能多地缓存,因此即使没有给出 Cache-Control,如果满足某些条件,响应也会被存储和重用。这称为启发式缓存

通常会根据响应头中的Date字段(报文创建时间)减去Last-Modified值的10%作为缓存时间

js 复制代码
max(0,(Date - Last-Modified)) % 10
  1. 硬性重新加载:还是html里直接引用的css,js重新拉取最新资源,其他css,js依旧是走默认的缓存策略

因此,没有配置nginx的情况下,默认没有强缓存,但是会触发启发式缓存和协商缓存

现在试试将强缓存取消

js 复制代码
 add_header Cache-Control "no-cache";

正常重新加载:没有进入启发式缓存直接走了协商缓存

硬性重新加载:跟上面一致

使用场景

对于文件名带hash的直接设置强缓存即可,因为如果文件改变文件名也会改变,会被当成一个新资源,另外一些第三方库,静态资源也可以设置久一点的强缓存。 其他不带hash的文件例如index.html就可以使用协商缓存

补充

在 webpack 中有三种生成哈希值规则的方式,可以用来区分文件是否修改。

  • hash 与整个项目有关,项目里有文件修改,所有文件的哈希值都会变化。
  • chunkhash 与入口有关,同一入口的文件被视为一个整体,当其中一个文件修改时,同入口的所有文件哈希值发生改变。
  • contenthash 只与文件内容有关,文件内容发生改变,才会更改该文件的哈希值。
相关推荐
Asort14 分钟前
JavaScript 从零开始(六):控制流语句详解——让代码拥有决策与重复能力
前端·javascript
无双_Joney33 分钟前
[更新迭代 - 1] Nestjs 在24年底更新了啥?(功能篇)
前端·后端·nestjs
在云端易逍遥35 分钟前
前端必学的 CSS Grid 布局体系
前端·css
ccnocare36 分钟前
选择文件夹路径
前端
艾小码36 分钟前
还在被超长列表卡到崩溃?3招搞定虚拟滚动,性能直接起飞!
前端·javascript·react.js
闰五月37 分钟前
JavaScript作用域与作用域链详解
前端·面试
泉城老铁41 分钟前
idea 优化卡顿
前端·后端·敏捷开发
前端康师傅41 分钟前
JavaScript 作用域常见问题及解决方案
前端·javascript
司宸42 分钟前
Prompt结构化输出:从入门到精通的系统指南
前端