前端缓存

前端缓存分为浏览器缓存和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 只与文件内容有关,文件内容发生改变,才会更改该文件的哈希值。
相关推荐
bin91538 分钟前
前端JavaScript导出excel,并用excel分析数据,使用SheetJS导出excel
前端·javascript·excel
Rattenking16 分钟前
node - npm常用命令和package.json说明
前端·npm·json
Easonmax16 分钟前
【HTML5】html5开篇基础(1)
前端·html·html5
For. tomorrow20 分钟前
Vue3中el-table组件实现分页,多选以及回显
前端·vue.js·elementui
布瑞泽的童话1 小时前
无需切换平台?TuneFree如何搜罗所有你爱的音乐
前端·vue.js·后端·开源
白鹭凡1 小时前
react 甘特图之旅
前端·react.js·甘特图
打野赵怀真1 小时前
你有看过vue的nextTick源码吗?
前端·javascript
2401_862886781 小时前
蓝禾,汤臣倍健,三七互娱,得物,顺丰,快手,游卡,oppo,康冠科技,途游游戏,埃科光电25秋招内推
前端·c++·python·算法·游戏
书中自有妍如玉1 小时前
layui时间选择器选择周 日月季度年
前端·javascript·layui