前端HTTP缓存你真的了解吗?强缓存?协商缓存?启发式缓存?

背景

HTTP缓存,一个老生常谈的话题,一个高频出现的面试题,一个强缓存、协商缓存简单几句话就能概括的缓存机制,一个所有前端页面都需要用到却又极少被关注的功能。它远比想象中更强大,更智慧,更重要。本文将和大家一起感受HTTP缓存的智慧和魅力,一起彻彻底底的搞清楚HTTP缓存的机制,一起使用它来提升咱们的项目性能。

HTTP缓存是客户端和服务端通信的一种缓存,可以将网页访问产生的数据缓存到内存或本地。合理利用这一缓存可以提升资源重复利用率,减少网络带宽,降低服务器压力,提升客户端响应速度。

请求头&响应头

在介绍HTTP缓存之前,我们先来了解一下请求头和响应头与HTTP缓存之间的关系。如下图所示,一个请求通常会包含一个响应头(Response Headers),一个请求头(Request Headers),可以看到请求头和响应头中都包含了很多字段,这些字段称为首部字段,其中有一些就是和HTTP缓存相关的,后面我会将相关字段都提取出来。

HTTP缓存总的来说可以分为两大类,一类是强缓存,一类是协商缓存。强缓存和协商缓存的设置,都存放于请求头和响应头中的首部字段,相关的字段我做成了思维导图。可以看到,和HTTP缓存相关的字段还是比较多的,初次看到可能一头雾水,不用担心,后面在讲强缓存和协商缓存部分的时候,我会一一解释各字段的含义。

强缓存

我们第一次打开某个网站,加载速度会比较慢,再次访问时能明显感觉到加载速度较第一次更快速,这就是强缓存在起作用。画两张时序图描述一下强缓存生效和未生效的流程。

  • 强缓存未生效
  • 强缓存生效

说了这么多,我们打开浏览器实操一下,看一下在浏览器中强缓存生效和失效的实际表现。

首次加载,强缓存未生效

我们清除一下缓存(Chorm浏览器打开开发者工具后,刷新图标右键,选择清空缓存并硬性重新加载)模拟首次加载,可以在network面板看到资源的加载情况。我们重点关注一下Size和Time列的数据,Size列表示从服务器获取资源的大小,Time列表示资源加载耗时,可以看到第一次加载时,几乎每个资源都是从服务器获取,所以打开速度会受到影响,资源加载总耗时3.34s。

第二次加载,强缓存生效

第二次访问该网站的时候,大多数资源的Size都变成了 Memory cache 和 Disk cache , 并且加载时间Time也极大的缩短,资源加载总耗时也由之前的3.34s变为了1.98s。

首部字段解析

从上文中可以看出,合理设置强缓存可以减少不必要的服务端请求,提升网页打开速度。设置强缓存的奥秘就在于请求头和响应头中的首部字段,一起来看一下和强缓存相关的首部字段吧。

  • Expires 首部字段是 HTTP/1.0 中定义缓存的字段,其给出了缓存过期的绝对时间,即在此时间之后,响应资源过期。

  • Cache-Control 首部字段是 HTTP/1.1 中定义缓存的字段,其用于控制缓存的行为,可以组合使用多种指令,多个指令之间可以通过 "," 分隔,常用的指令有:max-age、s-maxage、public/private、no-cache/no store 等。

    • max-age: 给出了缓存的相对时间,单位为秒,即获得响应之后多少秒后过期,和Expires同时出现时,max-age优先级更高。
    • s-maxage:对公共缓存服务器生效,表示该资源在公共服务器中缓存的相对时间。如果存在公共缓存服务器,浏览器缓存失效后,会先请求公共缓存服务器,公共缓存服务器失效后会重新请求资源服务器更新公共缓存服务器中的资源,然后返回给浏览器。
    • public:表示可以被任何节点缓存,包括客户端和公共缓存服务器。
    • private:表示该资源只能被客户端(浏览器)缓存。
    • no-cache :表示客户端每次使用缓存资源前必须向服务器确认其有效性。
    • no-store :表示不缓存资源。

下图展示了一个缓存有效期为一年的资源,31536000秒/60*60/24 = 365 天

协商缓存

了解完强缓存后,接下来继续聊聊协商缓存,协商缓存和强缓存并不是两个相对独立的概念,两者有着密不可分的联系。协商缓存是在强缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识来决定是否使用缓存。还是用时序图来描述一下协商缓存生效、未生效的流程。

  • 协商缓存未生效
  • 协商缓存生效

首部字段解析

和协商缓存相关的首部字段主要有4个,Last-Modified 与 If-Modified-Since,Etag 与 If-None-Match。

  • Last-Modified:代表资源最后修改时间,存在服务端返回的响应头。
  • If-Modified-Since:存在客户端请求头,值为上次存储的Last-Modified,判断资源是否过期。
  • Etag: 代表资源的唯一标识,存在服务端返回的响应头,Etag优先级高于Last-Modified。
  • if-None-Match: 存在客户端请求头,值为上次存储的Etag,判断资源是否过期。

彩蛋:启发式缓存

在强缓存的章节中,我们了解到了缓存有效期由ExpiresCache-Control中的max-age 来决定的,那么如果响应头中不存在这两个字段,缓存的有效期怎么计算呢?浏览器还会走强缓存吗?答案是肯定的,这就是我们要现在要了解的启发式缓存

当报头中没有用来确定强缓存时间的字段时,浏览器会触发启发式缓存,缓存有效期计算公式:**(date - last-modified ) * 10%,**取响应报头中 date 与 last-modified 值之差的百分之十作为缓存时间。启发式缓存比较容易忽略,不了解启发式缓存可能会因为这种默认的缓存方式而掉入坑里,但一旦你了解了浏览器启发式缓存的机制,很多问题都可以得到解决。

总结

本文首先介绍了和HTTP缓存息息相关的请求头和响应头 ,接下来引出了两种缓存方式,强缓存协商缓存 ,并介绍了他们的运行流程以及关键首部字段,最后提出了很容易忽略的启发式缓存,希望本文能够对你有帮助。

相关推荐
正小安19 分钟前
如何在微信小程序中实现分包加载和预下载
前端·微信小程序·小程序
_.Switch2 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
一路向前的月光2 小时前
Vue2中的监听和计算属性的区别
前端·javascript·vue.js
长路 ㅤ   2 小时前
vite学习教程06、vite.config.js配置
前端·vite配置·端口设置·本地开发
长路 ㅤ   2 小时前
vue-live2d看板娘集成方案设计使用教程
前端·javascript·vue.js·live2d
Fan_web2 小时前
jQuery——事件委托
开发语言·前端·javascript·css·jquery
安冬的码畜日常2 小时前
【CSS in Depth 2 精译_044】第七章 响应式设计概述
前端·css·css3·html5·响应式设计·响应式
莹雨潇潇3 小时前
Docker 快速入门(Ubuntu版)
java·前端·docker·容器
Jiaberrr3 小时前
Element UI教程:如何将Radio单选框的圆框改为方框
前端·javascript·vue.js·ui·elementui
Tiffany_Ho4 小时前
【TypeScript】知识点梳理(三)
前端·typescript