HTTP | 强缓存与协商缓存

news2025/1/11 14:52:54

缓存,开发绕不开的环节。

web缓存分为很多种,比如数据库缓存、代理服务器缓存、CDN缓存,以及浏览器缓存(localStorage, sessionstorage, cookie)。

一个web应用,需要各式各样的资源(html/css/js, 图片,字体,。。。),浏览器在取这些资源都是通过http请求完成。为了给用户好的体验,需要让这些请求尽可能快和少(减少冗余请求)。HTTP缓存机制就是 针对不同资源类型,采取不同的缓存策略,避免不必要的请求!

常见的 HTTP 缓存只能存储 GET 响应,对于其他类型的响应则无能为力。缓存的关键主要包括request method和目标URI(一般只有GET请求才会被缓存)。

浏览器在每次GET URL时都会先检查URL对应的缓存,除非你指定不使用缓存(强制刷新或者Disable Cache等)

缓存的位置主要是内存和磁盘(本文中用 本地 指代)

浏览器会把哪些文件丢进内存中?哪些丢进硬盘中?
关于这点,网上说法不一,不过以下观点比较靠得住:
对于大文件来说,大概率是不存储在内存中的,反之优先
当前系统内存使用率高的话,文件优先存储进硬盘

HTTP 缓存分为以下两种,两者都是通过 HTTP 响应头控制缓存。

  1. 强制缓存
  2. 协商缓存

强制缓存

当web应用获取资源时,先从 本地 获取,如果有就直接用,否则,重新发起请求。

返回的状态码为200, 如果是从缓存中获取会有标记(来自内存缓存/来自磁盘缓存)。从内存当中获取的,浏览器关闭后该资源内存会被释放;从磁盘中读取的,关掉浏览器资源依然在。

强制缓存涉及到的头字段有 Expires(http1.0)和Cache-Control(http1.1),由服务端设置.

Expires

接受一个 GMT 格式时间

Expires: Wed, 21 Oct 2015 07:28:00 GMT

无效的日期,比如 0,代表着过去的日期,即该资源已经过期。

服务端设置该字段,然后该资源在本地缓存。每次要获取该资源时,就会检查该字段,有效期内直接用否则重新向服务端获取。

注意: 如果在Cache-Control响应头设置了 “max-age” 或者 “s-max-age” 指令,那么 Expires 头会被忽略。

Cache-Control

此字段拥有强大的缓存控制能力。常见的字段有

  • max-age:设置强制缓存的时间,单位s。资源会缓存到本地。
  • no-cache:设置不强制缓存,每次都去进行协商缓存,确定资源是否有变更,一般用在index.html。 资源会缓存到本地。
  • no-store:不进行强制缓存和协商缓存,直接拉取最新的资源。资源不缓存到本地。
  • private:如果有这个字段 比如:Cache-Control: private, max-age=360000,意思:中间层(代理)或者说CDN 不缓存此资源,使CDN失效,每次只能访问源服务器; 客户端可以缓存。
  • public:CDN可以缓存: 客户端和代理服务器都可以缓存。

更多字段见 Cache-Control - HTTP | MDN

客户端请求资源时,

首次请求:服务端在资源返回时设置 http header 属性 Cache-Control 的值(response header),通常设置 max-age =xxx 开启强缓存。客户端根据 Cache-Control 的值对各种资源采取相应的缓存策略,对强缓存的资源在本地缓存起来。

二次请求:直接从本地拿。

注意max-age 优先级要大于 Expires

补张图,别的地方拿的

强制缓存

协商缓存

协商缓存又称对比缓存、弱缓存。

涉及到的header 主要有

  • Last-Modified/If-Modified-Since(http1.0),匹配 Response Header 的 Last-Modified 与 Request 的 If-Modified-Since 是否一致
  • Etag/If-None-Match(http1.1),匹配 Response Header 的 Etag 与 Request 的 If-None-Match 是否一致

Last-Modified/If-Modified-Since

Last-Modified 表示上一次 的修改时间。

客户端请求资源时

首次请求:服务端返回资源,在响应头(Response header)附带有 Last-Modified 属性,客户端拿到并在本地缓存(资源和Last-Modified标识)。

二次请求:只会发送header。请求头(Request header)自动带上 If-Modified-Since, 值为 服务器返回的 Last-Modified 的值。服务器做校对修改时间是否一致(If-Modified-Since == Last-Modified ?),资源没变即返回304,客户端从本地缓存中取,否则重新发送请求。

Etag/If-None-Match

Etag 表示 文件的唯一标识。

客户端请求资源时

首次请求:服务端返回资源,在响应头(Response header)附带有 Etag 属性,客户端拿到并在本地缓存(资源和 Etag 标识)。

二次请求:只会发送header。请求头(Request header)自动带上 If-None-Match, 值为 服务器返回的 Etag 的值。服务器做校对文件唯一标识是否一致(If-None-Match == Etag ?),资源没变即返回304,客户端从本地缓存中取,否则重新发送请求。

Etag 要优于 Last-Modified,原因如下

  • Last-Modified 最细的时间粒度为 S,Etag 有更细的时间粒度。

  • 在1s内,如果某资源被修改(一次或者多次),Last-Modified 会错误的复用缓存,Etag 不会

http1.1版本 推出的 Etag 就是解决 http1.0 版本Last-Modified 存在的上述问题。

当然 Etag 也有缺点

  • 计算 Etag 值需要性能损耗;

  • 分布式服务器时依赖算法:分布式服务器存储的情况下,计算 Etag 的算法如果不一样,会导致浏览器从一台服务器上获得页面内容后到另外一台服务器上进行验证时现 Etag 不匹配的情况。

注意: Etag 优先级大于 Last-Modified

总结

强制缓存优先于协商缓存

简单理解,协商缓存就是每次都会每次请求资源时客户端都会去问服务器,资源能用吗(是否被修改),我要用最新的。

协商缓存需要配合 设置 Cache-Control:no-cache 使用(这一点,我是在 利用 koa 模仿缓存场景得出的)

补张图

协商缓存

一些场景

常见操作

  • 新开页面窗口/前进后退/链接跳转/输入 url 回车:根据实际缓存策略处理,没有设置 no-cache 或 no-store,默认先走强制缓存路线
  • 按钮刷新,F5 刷新,右键重新加载:将 cache-control 的 max-age 直接设置成了 0,让缓存立即过期,直接走协商缓存路线
  • ctrl+F5 强刷:浏览器会强行设置 no-store,强制获取最新的资源。 同 控制台设置 禁用缓存 F5刷新。

常见策略配置

频率可能会频繁更改,需要每次都询问。可能每月修改几乎不变
Cache-Controlprivate, no-cachePublic, max-age=31536000 (一年甚至永久)Public, max-age=31536000 (一年甚至永久),stale-while-revalidate(实验性字段)=86400
使缓存失效每次都要询问,确保最新改名字(hash值)改名字(hash值)
Cache-Control: max-age=315360000
使用场景:CDN(一般永远不变)
效果:缓存10年(强缓存)

Cache-Control: max-age=31536000
使用场景:比如图片资源(几乎不变)
效果:缓存1年(强缓存)

Cache-Control: max-age=2592000
使用场景:比如js,css资源(按月迭代,较少频率改变)
效果:缓存1月(强缓存)

Cache-Control: no-cache
使用场景:webpack工程的 SPA单页面的入口 index.html(可能频繁改变)
效果:每次都要发起协商缓存,去询问资源是否变更,无变更则304重定向(协商缓存)

缓存大致流程

图片描述

结尾

这种文章属于烂大街的文章,建议多阅读几篇。为了更好的理解http缓存,自己输出文章理解能比较深刻。

文末,写本文的过程中也解决了我的一些疑问:

  • 本地空间(内存、磁盘)是浏览器在操作(缓存资源,获取标识,判断标识等)。这是个愚蠢的问题😂

  • 协商缓存,缓存命中后向服务器发送的校验请求只有header(携带 Etag/Last-Modified)而无body

详见 前端 - HTTP缓存的疑问? - SegmentFault 思否

协商缓存要配合强缓存使用,如果不开启强缓存使用,协商缓存没有意义

大部分web服务器默认开启协商缓存,且是同时开启last-modifiedEtag

缓存都是服务端控制,设置响应头部,客户端执行相应缓存策略。前端能做的事微乎其微,不过了解缓存机制对我们日常开发还是有帮助的。如果前端有 nginx 权限,那么就可以在http 缓存上大刀阔斧的优化。

网上看了许多文章,这里一一感谢👏🏻👏🏻👏🏻。

HTTP 缓存 - HTTP | MDN

什么是强缓存和协商缓存 - 掘金

浏览器缓存 - Javascript 编程基础 - SegmentFault 思否

什么是强缓存和协商缓存 - 掘金

如何制定前端资源的最佳缓存策略? - 掘金

浅谈 强制缓存/协商缓存 怎么用? - 掘金

前端面试常见的浏览器缓存(强缓存、协商缓存),代码实操 - 掘金

不废话,代码实践带你掌握 强缓存、协商缓存! - 掘金

史上最详细的经典面试题 从输入URL到看到页面发生了什么? - 掘金

浏览器缓存:memory cache、disk cache、强缓存协商缓存等概念_(memory cache)_Lvan的前端笔记的博客-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/436451.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++】C++11 右值引用和移动语义

文章目录 一、左值与左值引用二、右值与右值引用三、左值引用和右值引用的比较四、右值引用的使用场景和意义1、左值引用的短板2、移动构造和移动赋值3、STL 容器的变化 五、万能引用与完美转发1、万能引用2、完美转发 六、新增默认成员函数七、成员变量的缺省值八、default 和…

【Blender建模】newbird从零开始学+新手常见问题处理

目标 第一阶段:在跟着教程下,熟悉如何使用blender 教程地址:https://www.youtube.com/watch?vnIoXOplUvAw 一、移动、旋转、扩展各视角下的物体,熟悉各个窗口 鼠标中键(Shift)控制视角的方向 ~键快速选择…

Redis --- 入门、数据类型

一、前言 1.1、什么是Redis Redis是一个基于内存的key-value结构数据库。Redis 是互联网技术领域使用最为广泛的存储中间件,它是「Remote Dictionary Service」的首字母缩写,也就是「远程字典服务」。 基于内存存储,读写性能高适合存储热点…

Pytorch基础 - 5. torch.cat() 和 torch.stack()

目录 1. torch.cat(tensors, dim) 2. torch.stack(tensors, dim) 3. 两者不同 torch.cat() 和 torch.stack()常用来进行张量的拼接,在神经网络里经常用到。且前段时间有一个面试官也问到了这个知识点,虽然内容很小很细,但需要了解。 1. t…

Spring(10. 面试问题简析)学习笔记

上一篇:9. Spring 底层原理 文章目录 1. 对Spring的IOC机制的理解2. 对spring的AOP机制的理解3. 了解过cglib动态代理吗?他跟jdk动态代理的区别是什么?4. 能说说Spring中的Bean是线程安全的吗?5. Spring的事务实现原理是什么&…

Leetcode-二叉树

1.中序-后序构建二叉树 106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode) 1. 首先根据后序(左右中)确定顶点元素; 2. 根据顶点元素划分中序序列; 3. 根据划分中序序列中-左子树的长度,进…

半小时学会HTML5

一、了解几个概念 1、HTML定义 HTML是(Hyper Text Markup Language)超文本标记语言,超文本包含:文字、图片、音频、视频、动画等。 2、W3C 是什么? W3C 即(World Wide Web Consortium) 万维…

【性能测试】常见适用场景以及策略

面对日益复杂的业务场景和不同的系统架构,前期的需求分析和准备工作,需要耗费很多的时间。而不同的测试策略,也对我们的测试结果是否符合预期目标至关重要。 这篇博客,聊聊我个人对常见的性能测试策略的理解,以及它们…

RK3399 Android 10 Camera2保存录像时缩略图获取为空

RK3399 Android 10相机录像保存时无法获取缩略预览图 先找到录像点击按钮 //点击快门按钮时可以通过log打印看到停止录像的流程onShutterButtonClick() //这里主要看停止的流程即stop true时会进入onStopVideoRecording方法 public void onShutterButtonClick() {Log.d(TAG…

【HAL库】BMP180气压传感器+STM32,hal库移植

BMP180气压传感器STM32 1 导入.c.h文件(不再赘述,详细见LED部分)2 Cubemx配置3 修改 .h 文件4 测试 将BMP180从标准库移植到HAL库。模拟IIC。 极简工程代码如下: https://github.com/wyfroom/HAL_BMP180 该份代码硬件配置&#x…

C++——深入探究函数重载

文章目录 概述函数重载函数重载的概念函数重载的细节 C支持函数重载的原理——名字修饰(name Mangling) 概述 本篇博客讲诉的是c函数重载是什么,以及了解其种的一些特征以及重载函数的意义,并且运用linux中的g编译器简单探究一下函数重载底层是如何实现的…

线性表之顺序表(增删查改)详解

🍕博客主页:️自信不孤单 🍬文章专栏:数据结构与算法 🍚代码仓库:破浪晓梦 🍭欢迎关注:欢迎大家点赞收藏关注 文章目录 🍉线性表🍒顺序表1. 概念及结构2. 接口…

数据库JDBC

数据库厂商提供一个程序来完成 API 的转换,对原生 API 封装再提供成JDBC 的形状。 这个程序叫数据库驱动包。 JAVA程序员要想对数据库开发, 就要导入对应的数据库驱动包,才能编写代码。 数据库驱动是让JDBC认识数据库API URL 计算机里的一…

MySQL安装与新用户的创建相关

一、MySQL安装 1. 官网下载mysql的ims包 MySQL :: Download MySQL Installer (Archived Versions) 下载好,双击运行。 2. 根据提示进行安装 这里选择手动安装的选项: 然后选择你安装的MySQL版本,这里是5.7 勾选自定义MySQL安装位置 下一…

教育大数据总体解决方案(7)

考勤查询 创客教室 为体现学校创新教育的成果,丰富学校创新实践活动,加强创新课程普及教育,把机器人创新教育作为学校的教育特色来体现,使学生通过理论与实践相结合的方法,进一步学习掌握机械、电子结构、信息技术、人…

让我们谈谈你对 ThreadLocal 的理解

介绍 ThreadLocal 从 JDK1.2 开始,ThreadLocal 是一个被用来存储线程本地变量的类。在 ThreadLocal 中的变量在线程之间是独立的。当多个线程访问 ThreadLocal 中的变量,它们事实上访问的是自己当前线程在内存中的变量,这能确保这些变量是线…

基于鲸鱼算法的极限学习机(ELM)回归预测-附代码

基于鲸鱼算法的极限学习机(ELM)回归预测 文章目录 基于鲸鱼算法的极限学习机(ELM)回归预测1.极限学习机原理概述2.ELM学习算法3.回归问题数据处理4.基于鲸鱼算法优化的ELM5.测试结果6.参考文献7.Matlab代码 摘要:本文利用鲸鱼算法对极限学习机进行优化,并…

kettle——数据清洗(数据表——>转换——>数据表)

目录 1、表输入 ①点击“新建”选项,新建数据库 ②选择“获取SQL” ③选择表a ④注意:字段只显示了5个,而一共有6个字段,money字段需要手动添加 2、转换 ①打开java 控件,设置变量 3、表输出 ①连接表b ②映…

【Redis7】Redis7 复制(重点:复制原理)

【大家好,我是爱干饭的猿,本文重点介绍Redis7 复制。 后续会继续分享Redis7和其他重要知识点总结,如果喜欢这篇文章,点个赞👍,关注一下吧】 上一篇文章:《【Redis7】Redis7 事务&管道&…

Git入门指南(手把手教学)

Git入门指南 一、什么是Git二、Git的安装下载三、git的简单实践1.创建git仓库2.Windows上生成公钥以绑定GitHub仓库3.写一个Helloworld 四、帮助学习的网站 一、什么是Git Git是一种分布式版本控制系统,它是由Linus Torvalds为了管理Linux内核开发而开发的。与中心化…