先看一些概念性的术语:

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

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

再验证:原始服务器上内容可能会发生变化,缓存需要对副本进行检测,看是否为最新的,这种“新鲜度检测”叫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. Hibernate Validator校验参数全攻略

    1. 前言 数据字段一般都要遵循业务要求和数据库设计,所以后端的参数校验是必须的,应用程序必须通过某种手段来确保输入进来的数据从语义上来讲是正确的. 2. 数据校验的痛点 为了保证数据语义的正确,我们 ...

  2. MR程序的几种提交运行模式

    本地模式运行 1-在windows的eclipse里面直接运行main方法 将会将job提交给本地执行器localjobrunner 输入输出数据可以放在本地路径下 输入输出数据放在HDFS中:(hd ...

  3. Php7+Mysql8实现简单的网页聊天室功能

    php聊天室 前端页面 chat_room.html <!DOCTYPE html> <html lang="en"> <head>     & ...

  4. HashMap源码(数组算法)

    Jdk1.8初始化hashMap容量的算法 static final int tableSizeFor(int cap) { // 先减1,避免传进来的本来就是2的n次幂,导致算出来多了一次幂,比如传 ...

  5. 串口通信—USB转串口

    如何使用c库printf

  6. 老板让我从上千个Excel中筛选数据,利用Python分分钟解决!

    大家好,又到了Python办公自动化系列. 今天分享一个真实的办公自动化需求,大家一定要仔细阅读需求说明,在理解需求之后即可体会Python的强大! 很多人学习python,不知道从何学起.很多人学习 ...

  7. Flutter 容器(5) - SizedBox

    SizedBox: 两种用法:一是可用来设置两个widget之间的间距,二是可以用来限制子组件的大小. import 'package:flutter/material.dart'; class Au ...

  8. 解决AndroidStudio 模拟器无网络连接

    更新 注意 Win10 要在cmd下打开, 也就是地址栏打cmd能成功 转载地址 https://blog.csdn.net/Bibifeng/article/details/81317037 最近写 ...

  9. Linux学习笔记 一 第三章 Linux常用命令

    第三章Linux常用命令 一.文件处理命令 1.命令格式 2.目录处理命令:ls 3.目录处理命令:mkdir 4.文件处理命令: touch

  10. 性能测试必备知识(10)- Linux 是怎么管理内存的?

    做性能测试的必备知识系列,可以看下面链接的文章哦 https://www.cnblogs.com/poloyy/category/1806772.html 内存映射 日常生活常说的内存是什么 比方说, ...