先看一些概念性的术语:

命中率:由缓存提供服务的请求所占的比例被称为缓存命中率;

缓存未命中:其实就是一些到达缓存的请求没有副本可用,而被转发给原始服务器;

再验证:原始服务器上内容可能会发生变化,缓存需要对副本进行检测,看是否为最新的,这种“新鲜度检测”叫HTTP再验证;

缓存主要分为两类:

一,私有缓存

私有缓存是用户个人的缓存,Web浏览器中有内建的私有缓存,大部分浏览器将内容缓存到个人电脑的磁盘和内存中。这些缓存用来提供浏览器向前/向后、保存网页、查看源代码、离线浏览等功能。

二,公有代理缓存

公有缓存是多个用户使用,它是特殊的共享代理服务器,被称为缓存代理服务器,或被称为代理缓存。

缓存的基本步骤:

1,接收;

2,解析:将请求报文解析为片段;

3,查找;

4,新鲜度检测;

5,创建响应;

6,发送;

7,日志;

一,判断缓存是否过期:

1,cache-control: max-age=15400

max-age表示多少时间后过期,单位秒,这里是相对时间,既可以作为请求头,也可以作为响应头,如果请求头中设置max-age=0,表示立即过期,会进行新鲜度的校验,详细见后文。

还有一个s-maxage,仅适用于共享(公共)缓存

2,expires: Tue, 30 Jul 2019 04:59:34 GMT

表示什么时间后过期,这里是绝对时间,取决于用户当前系统时间,因此不建议单以这个为过期标准。

一般情况下,建议使用cache-control: max-age头,相对时间更好一些,如果两个标识都有,那么必须两个都过期了才算过期。

二,如果过期了,会进行新鲜度的校验:

当缓存资源过期时,缓存会向原始服务器发送一个条件请求GET,因为虽然当前缓存资源已经过期,但也有可能资源依然没有变化,所以不一定需要重新去获取资源,这时候就要做新鲜度的校验,对比缓存资源是否需要更新。

1,If-Modified-Since/Last-modified:Thu, 30 May 2019 11:44:49 GMT

这两个是搭配使用的,前者是请求头,后者是响应头,第一次返回数据时,响应头里会包含Last-modified字段,用来表示最近一次更新时间,当缓存资源过期时,缓存就会发送一个条件请求GET,请求头里带有If-Modified-Since,值就是Last-modified之前返回的值,如果检测发现服务器上资源文件最近修改时间和请求头里的这个时间一致,则不需要更新缓存,返回304状态码,这时候响应主体里是不会带有资源内容的,因为不需要更新,所以不返回,并重新更新缓存时间,就是上面说的cache-control: max-age和expires。如果不一致,则重新返回新的资源内容以及最近修改时间,并设置过期时间,状态码200.

2,If-None-Match/Etags: W/"d343901e56dedb646942d7f8d2a7df87"

对于大部分场景,Last-modified是满足的,但是对于一些特殊场景,那么就有问题了:

1️⃣亚秒级别的资源更新,时间相关的,因为Last-modified只能精确到秒级,所以无法精准;

2️⃣对于一些资源的更新,如果只是更新了一些无关紧要的小内容,那其实没必要重新更新缓存资源,我们允许继续使用旧的缓存,那这时候实际上就是一种弱检查;

Etags会返回一段hash的字符串,用来标识当前资源,如果缓存过期,那么If-None-Match就会带上Etags第一次返回过来的值,然后去和服务器上的tag作对比,如果发现不一致,则重新返回资源并更新缓存,如果没有变化,则返回304,更新缓存过期时间。这里示例代码里加了一个W,就表示这是一条弱检查。

但是大部分场景,我们还是使用If-Modified-Since/Last-modified来判断是否需要更新过期资源。

三,强制更新或取消缓存

这里还是用到cache-control头,这里作为请求头

no-store:禁止使用缓存,清除缓存资源,重新去原始服务器上去获取资源;

no-cache:在进行新鲜度校验之前,不能使用缓存。和no-store不一样的是,no-cache并不是不缓存,而是缓存了但是不使用,在新鲜度校验成功后才可以使用缓存;

must-revalidate:在缓存资源过期之后,必须进行新鲜度校验,这里是必须过期之后才起作用;过期后强制校验;(没什么用)

再补充一个stale-while-revalidate: 它表示允许缓存过期后的一段时间内继续使用,同时会发起一个异步新鲜度二次校验,如果资源更改了,那么下次访问的时候就能拿到一个新鲜的,但如果过期时间没有超过stale-while-revalidate给出的时间,第一次的时候一定是取的缓存,这种策略是用速度换取了内容的新鲜程度,需要谨慎使用。

这里补充一个Chrome里的知识点:

我们一般打开一张图片,如果是首次打开,这里就是一个正常的请求,状态码200,图片大小正常,size有值。

但是当我们关掉这个浏览器,再重新打开一个,再次访问刚刚的图片地址,状态码200,会发现这里的size变成了from disk cache,这里表示已经缓存到本地硬盘里中了,所以会直接读取硬盘里的缓存图片,然后返回的报文也是之前缓存的时候的报文。

当我们刷新这个页面,会发现状态码变成了304,size有值了,但是和第一次打开的时候不一样,那么根据之前讲的,304说明浏览器进行了缓存的新鲜度二次校验,那么我们可以猜测,浏览器在刷新的时候,会发一个cache-control: no-cache的请求,进行一个二次新鲜度校验,这里发现图片资源未改变,所以不会重新获取资源,而是继续读取本地缓存,所以状态码为304,而大小为什么不是原图大小,因为二次校验的时候,条件请求如果为否,则不会返回完整资源。

这里应该还有一个size情况是from memory cache,表示是从内存里读取的缓存,这里我没有找到截图,它和from disk cache的区别就是内存里的缓存优先级更高一些,但是如果浏览器关闭,则会清掉,而disk cache是永久性的,除非手动删除硬盘上的缓存,不然一直存在,浏览器关掉也在。所以整个校验流程是:

1,浏览器内存中读取缓存;

2,本地硬盘上读取缓存;

3,从服务器拉取数据,并缓存到本地硬盘和内存中;

end

HTTP系列:缓存的更多相关文章

  1. 《吊打面试官》系列-Redis哨兵、持久化、主从、手撕LRU

    你知道的越多,你不知道的越多 点赞再看,养成习惯 前言 Redis在互联网技术存储方面使用如此广泛,几乎所有的后端技术面试官都要在Redis的使用和原理方面对小伙伴们进行360°的刁难.作为一个在互联 ...

  2. 《吊打面试官》系列-Redis常见面试题(带答案)

    你知道的越多,你不知道的越多 点赞再看,养成习惯 GitHub上已经开源,有面试点思维导图,欢迎[Star]和[完善] 前言 Redis在互联网技术存储方面使用如此广泛,几乎所有的后端技术面试官都要在 ...

  3. iOS图片加载速度极限优化—FastImageCache解析

    FastImageCache是Path团队开发的一个开源库,用于提升图片的加载和渲染速度,让基于图片的列表滑动 优化点 iOS从磁盘加载一张图片,使用UIImageVIew显示在屏幕上,需要经过以下步 ...

  4. iOS 图片加载速度极限优化—FastImageCache解析

    FastImageCache是Path团队开发的一个开源库,用于提升图片的加载和渲染速度,让基于图片的列表滑动起来更顺畅,来看看它是怎么做的.优化点iOS从磁盘加载一张图片,使用UIImageVIew ...

  5. 20191128 Spring Boot官方文档学习(9.9)

    9.9.数据存取 Spring Boot包含许多用于处理数据源的启动器. 9.9.1.配置自定义数据源 要配置自己的DataSource,请在配置中定义该类型的@Bean.Spring Boot可以在 ...

  6. prometheus远程写参数优化

    一.概述 prometheus可以通过远程存储来解决自身存储的瓶颈,所以其提供了远程存储接口,并可以通过过配置文件进行配置(prometheus.yml).一般情况下我们使用其默认的配置参数,但是为了 ...

  7. iOS 图片加载速度优化

    FastImageCache 是 Path 团队开发的一个开源库,用于提升图片的加载和渲染速度,让基于图片的列表滑动起来更顺畅,来看看它是怎么做的. 一.优化点 iOS 从磁盘加载一张图片,使用 UI ...

  8. Redis好文章推荐

    文章来源:掘金   作者:敖丙 Redis-避免缓存穿透的利器之BloomFilter <我们一起进大厂>系列- Redis基础 <我们一起进大厂>系列-缓存雪崩.击穿.穿透 ...

  9. 2020Java程序员架构师面试宝典,学习后面试必过,震惊,本人通过这篇教程,拿到了0个offer

    1. 引言 Java后端学习路线 <吐血整理>顶级程序员工具集 https://github.com/AobingJava/JavaFamily 跟上Java8 经历阿里.头条.腾讯等知名 ...

  10. CRL快速开发框架系列教程六(分布式缓存解决方案)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

随机推荐

  1. Python实现微信读书辅助工具

    [TOC] ##项目来源 这个有意思的项目是我从GitHub上找来的,起因是在不久前微信读书突然就设置了非会员书架数目上限,我总想做点什么来表达我的不满,想到可否用爬虫来获取某一本书的内容, 但是我技 ...

  2. HA模式下的java api访问要点

    在非HA架构的HDFS中,客户端要通过java接口调用HDFS时一般是在JobRunner的类中按照下面的方式: 因为nodename只有一个节点所以会在代码中显式的指明要连接哪一个节点:但是在HA模 ...

  3. 如何优雅的设计 Spring Boot API 接口版本号

    原文:https://blog.mariojd.cn/how-to-design-spring-boot-api-version-number-elegantly.html 一般来说,系统上线以后,需 ...

  4. .NET三层架构各项目之间的引用关系及如何添加引用?

    1.1三层之间的引用 整个.NET框架的项目创建完成之后,在开发之前,还需要建立各个项目之间的引用关系,以便在编写C#业务逻辑代码时调用相关项目的类库. 1.1.1 引用关系规则 .NET三层架构中的 ...

  5. css 命名规则 BEM!

    随着CSS的发展,使用CSS有语义化的命名约定和CSS层的分离,将有助于它的可扩展性,性能的提高和代码的组织管理.著作权归作者所有. BEM本质应该是一个css命名方案,最流行的命名规则之一就是BEM ...

  6. 每日一道 LeetCode (10):搜索插入位置

    每天 3 分钟,走上算法的逆袭之路. 前文合集 每日一道 LeetCode 前文合集 代码仓库 GitHub: https://github.com/meteor1993/LeetCode Gitee ...

  7. JavaScript 通过prototype改变原型的两种方式

    // -------------------- prototype 1 -------------------- function A(){} A.prototype.n = 1 let b = ne ...

  8. mysql基础测试题

    mysql基础测试题:https://www.cnblogs.com/wupeiqi/articles/5729934.html 如何创建表? 就这样类推?如何提取我们想要的元素呢? 综合提取呢?

  9. Java字符串中有多少个字符多少个char、字节

    Java 中Char是两个字节,Char在Java中也被称为代码单元(Code Unit) . Java中的字符与代码点(Code Unit)一 一对应,而可能对应一个或者两个 代码单元 字符串的le ...

  10. Vue.js中传值给子部件及触发动作的问题

    最近研究一个用vue.js做的程序并修改增加功能.其中用到传值给子部件等问题. template中有个子部件: <template> ...... <child-form  v-if ...