前端缓存

前端缓存分为浏览器缓存和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 只与文件内容有关,文件内容发生改变,才会更改该文件的哈希值。
相关推荐
Highcharts.js28 分钟前
如何下载使用Highcharts Grid 开发web可编辑表格
前端·人工智能·grid 表格·web 表格·在线编辑表格·highcharts表格安装·表格开发工具
用户62960593247051 小时前
从“浏览器根本区分不了”到真正实现:刷新不退出,关闭标签页自动退出,前端判断浏览器关闭和刷新
前端
qetfw1 小时前
MWU:Vue 3 + FastAPI 的 MaaFramework 跨平台 WebUI 源码
前端·vue.js·python·fastapi·开源项目·效率工具
mfxcyh1 小时前
Vue3+Ant Design Vue 实现手动异步文件上传(含大小校验、弹窗上传)
前端·javascript·vue.js
wordbaby1 小时前
Web端热敏标签打印完整解决方案(QZ Tray + 译维A42)
前端
swipe1 小时前
03|Axios 请求进了后端之后:Controller、Request、Response 是怎么接住它的?
前端·后端·全栈
meilindehuzi_a1 小时前
Vue3进阶基础:指令修饰符、v-model表单绑定、动态样式、计算属性与侦听器实战
前端·javascript·vue.js
csdn2015_1 小时前
vue 前端运行命令
前端·javascript·vue.js
swipe1 小时前
02|从 `pnpm dev` 到 Spring Boot 启动:后端服务到底怎么跑起来?
前端·后端·全栈
swipe2 小时前
01|前端人第一次打开 Spring Boot 项目,应该先看哪里?
前端·后端·全栈