当前位置: 首页 > news >正文

通俗易懂,一文学会前端缓存

什么是web缓存

主要分为:浏览器缓存、http缓存

其中http缓存是web缓存的核心,最难懂也是最重要的一部分。

浏览器缓存,如localStorage,sessionStorage,cookie等等。这些功能主要用于缓存一些必要的数据,比如用户信息,需要携带给后端的参数。(一般只能保存5M左右的数据,多了不行)

所以接下来,我们的重点将围绕http缓存展开。

缓存可以解决什么问题?缺点是什么?

可以解决的问题:

  • 减少不必要的网络传输,节约宽带(省钱小窍门)
  • 更快的页面加载速度(加速)
  • 减少服务器负载,避免服务器过载(减载)

存在的缺点:

  • 占内存(有些缓存会被存储到内存中)

http缓存又分为两种:

  • 强制缓存
  • 协商缓存

强制缓存

简称强缓存。如果浏览器判断请求的目标资源有效命中强缓存,如果直接命中,则可以直接从内存中读取目标资源,无需于服务器做任何通讯。

基于Expires字段实现的强缓存

Expires的作用是,设定一个强缓存时间,在此时间范围内,则从内存或磁盘中读取缓存返回。

但是Expires已经被废弃了!对于强缓存来说,Expires已经不是实现强缓存的首选。

因为Expires判断强缓存是否过期的机制是:获取本地时间戳,并对比先前拿到资源文件的Expires字段做比较,这里就存在一个巨大的bug:如果我的本地时间不准怎么办?

对,Expires太过于依赖本地时间,如果本地时间与服务器时间不同步,就会出现资源无法被缓存或者资源永远被缓存的情况。所以,Expires字段几乎不被使用了。在现在的项目中,我们并不推荐使用Expires,强缓存功能通常使用cache-control字段代替Expires。

没想到吧,说了半天,结果是给废弃的东西。

基于Cache-control实现的强缓存

Cache-control完美解决了Expires本地时间的bug。

Cache-control的使用方法很简单,只要在资源的相应头上写上需要缓存多久就好了:

res.writeHead(200,{
    'Cache-Control':'max-age=10'
});

从资源第一次返回的时候开始,往后的10s中内如果资源在此请求,则从缓存中读取。

Cache-Control:max-age=NN就是需要缓存的秒数。从第一次请求资源的时候开始,往后N秒内,资源若再次请求,则直接从磁盘(或内存中读取),不与服务器做任何交互。

Cache-control中max-age后面的值上一个滑动时间,从服务器第一次返回该资源开始倒计时,所以不需要对比客户端与服务器之间的时间,也就解决了Expires的巨大bug。

Cache-control的属性:

  • max-age:客户端资源被缓存多久
  • s-maxage:代理服务器缓存的时长
  • no-cache:强制进行协商缓存(直接跳过强缓存的校验)
  • no-store:禁止任何资源缓存
  • public:资源可被浏览器缓存,也可被代理服务器缓存
  • private:资源只能被浏览器缓存

⚠️注意:public与private互斥,默认为private;max-age与s-maxage不互斥,可以一起使用

协商缓存

协商缓存的内容会有点绕,我们仔细看看。

基于last-modified的协商缓存

过程:

  1. 首先需要在服务器端读出文件修改时间
  2. 将读出来的修改时间赋值给响应头的last-modified字段
  3. 最后设置Cache-control:no-cache

这个过程缺一不可。

还没结束,到这里还不能实现协商缓存。

当客户端读取到last-modified的时候,会在下次请求标头中携带一个字段If-Modified-Since,而这个请求头中的If-Modified-Since就是服务器第一次修改时候给他的时间。那么之后每次对该资源的请求,都会带上If-Modified-Since这个字段,而服务端需要拿到这个时间并再次读取资源的修改时间,让两者做对比决定上读取缓存还是返回新的资源。

使用以上方法的协商缓存存在两个非常明显的bug,这两个bug都是基于文件是通过对比修改时间来判断是否内容更改的。

  1. 因为是根据文件修改时间来判断,所以,在文件内容本身不修改的情况下,依然有可能更新文件修改时间,导致缓存失效了。
  2. 当文件在极短时间内完成修改(几百毫秒),而文件修改时间的最小单位是秒,所以这个时候文件修改时间不会改变,导致依然不会返回新的文件

为了解决这两个bug,从http1.1开始新增了一个头信息,ETag,顶住!!马上就顺通了!

基于ETag的协商缓存

ETag就是将原先协商缓存的比较时间戳的形式 -> 比较文件指纹

文件指纹:根据文件内容计算出的唯一哈希值,一旦内容改变哈市值随之改变,指纹也改变。

过程:

  1. 第一次请求资源的时候,服务端读取文件并计算出文件指纹,将文件指纹放在响应头的ETag字段跟资源一起返给客户端
  2. 第二次请求资源时,客户端自动从缓存中读取上一次服务器返回的ETag。并赋给请求头的if-None-Match字段,让上一次的文件指纹跟随请求一起回到服务端
  3. 服务端拿到请求头的if-None-Match字段值,并再次读取目标资源生成文件指纹,两个指纹做对比,如果完全一致,则直接返回304状态码和一个空的相应体;如果不吻合,则说明文件被修改,那么将新的文件指纹放在响应头的ETag中返回给客户端

ETag也有缺点

  • ETag需要计算文件指纹,服务端需要更多的计算开销,如果文件尺寸大,数量多,计算频繁的话,ETag计算就会影响服务端性能,在这种场景下就不太适用
  • ETag又强验证和弱验证,所谓强验证,ETag生成的哈希码深入到每个字节。哪怕文件中只有一个字节改变了,也会生成不同的哈希值,所以强验证非常消耗计算量;弱验证是提取文件的部分属性来生成哈希值,因为不必精确到每个字节,所以整体速度较快,但准确率不高。

总结一下

  • http缓存可以减少带宽流量,加快响应速度
  • 关于强缓存,cache-control是Expires的完全替代方案,在可以使用cache-control的情况下不要使用expires
  • 关于协商缓存,etag并不是last-modified的完全替代方案,而是补充方案,具体用哪一个,取决于业务场景
  • 有些缓存是从磁盘读取,有些缓存是从内容中读取,有什么区别?从内存中读取的缓存更快
  • 所有带304的资源都是协商缓存,所有标注从内存/磁盘中读取的资源都是强缓存

相关文章:

  • python常用基础笔记
  • centos设置root免密自动登陆
  • JuiceFS 在多云存储架构中的应用 | 深势科技分享
  • 【LeetCode】思维向题笔记总结(持续更新)
  • springboot+vue农产品销售配送网站
  • ISE的FPGA程序加载与固化——Omapl138/TMS320C6748+FPGA核心板
  • SAP ABAP 定义事件以及处理事件
  • 西瓜书-2习题
  • 中国LED封装行业发展前景预测与投资战略规划分析报告
  • 传出神经系统分为哪两类,传出神经的分类与功能
  • [最新]ubuntu22.04安装kubernetes1.25 k8s1.25
  • 个人整理前端代码规范
  • 中国图书零售连锁行业市场前瞻与投资战略规划分析报告
  • Linux开发工具 - vim篇
  • python各种编辑器、APP、软件下载
  • [译] React v16.8: 含有Hooks的版本
  • axios 和 cookie 的那些事
  • ECMAScript入门(七)--Module语法
  • Hexo+码云+git快速搭建免费的静态Blog
  • php中curl和soap方式请求服务超时问题
  • Python3爬取英雄联盟英雄皮肤大图
  • SQLServer插入数据
  • uni-app项目数字滚动
  • XML已死 ?
  • 第三十一到第三十三天:我是精明的小卖家(一)
  • 分类模型——Logistics Regression
  • 面试题:给你个id,去拿到name,多叉树遍历
  • 使用 Docker 部署 Spring Boot项目
  • 新手搭建网站的主要流程
  • ​​​​​​​ubuntu16.04 fastreid训练过程
  • #控制台大学课堂点名问题_课堂随机点名
  • (1)STL算法之遍历容器
  • (12)Hive调优——count distinct去重优化
  • (Git) gitignore基础使用
  • (Mirage系列之二)VMware Horizon Mirage的经典用户用例及真实案例分析
  • (八)光盘的挂载与解挂、挂载CentOS镜像、rpm安装软件详细学习笔记
  • (附源码)springboot工单管理系统 毕业设计 964158
  • (附源码)springboot教学评价 毕业设计 641310
  • (个人笔记质量不佳)SQL 左连接、右连接、内连接的区别
  • (四)图像的%2线性拉伸
  • (转)为C# Windows服务添加安装程序
  • .bat批处理(十):从路径字符串中截取盘符、文件名、后缀名等信息
  • .NET Core中Emit的使用
  • .Net IOC框架入门之一 Unity
  • .Net 垃圾回收机制原理(二)
  • .net图片验证码生成、点击刷新及验证输入是否正确
  • [ vulhub漏洞复现篇 ] JBOSS AS 5.x/6.x反序列化远程代码执行漏洞CVE-2017-12149
  • [20160807][系统设计的三次迭代]
  • [2018/11/18] Java数据结构(2) 简单排序 冒泡排序 选择排序 插入排序
  • [BZOJ] 3262: 陌上花开
  • [C#]扩展方法
  • [C#]手把手教你打造Socket的TCP通讯连接(一)
  • [C#]无法获取源 https://api.nuge t.org/v3-index存储签名信息解决方法
  • [C++]Leetcode17电话号码的字母组合
  • [element-ui] el-dialog 中的内容没有预先加载,因此无法获得内部元素的ref 的解决方案