igCircle Blog

强缓存和协商缓存

2021年9月6日

14分钟阅读

2 次浏览

0 条评论

浏览器

标签

浏览器

1 为什么要使用浏览器缓存 - 减少了冗余的数据传输,节省了流量 - 减少了服务器的负担,大大提升了网站的性能 - 加快了客户端加载网页的速度 - 更好的用户体验 2 浏览器缓存类型 浏览器缓存主要有两类:缓存协商和彻底缓存,也有称之为协商缓存和强缓存。 强缓存:强制缓存整体流程比较简单,就是在第一次访问服务器取到数据之后,在过期时间之内不会再去重复请求。实现这个流程的核...

1 为什么要使用浏览器缓存

  • 减少了冗余的数据传输,节省了流量

  • 减少了服务器的负担,大大提升了网站的性能

  • 加快了客户端加载网页的速度

  • 更好的用户体验

2 浏览器缓存类型

浏览器缓存主要有两类:缓存协商和彻底缓存,也有称之为协商缓存和强缓存。

强缓存:强制缓存整体流程比较简单,就是在第一次访问服务器取到数据之后,在过期时间之内不会再去重复请求。实现这个流程的核心就是如何知道当前时间是否超过了过期时间。

  • http1.0 强制缓存通过 Expires 响应头来实现

  • http1.1 强制缓存通过 Cache-Control 响应头来实现。

    协商缓存:协商缓存与强制缓存的不同之处在于,协商缓存每次读取数据时都需要跟服务器通信,并且会增加缓存标识。在第一次请求服务器时,服务器会返回资源,并且返回一个资源的缓存标识,一起存到浏览器的缓存数据库。当第二次请求资源时,浏览器会首先将缓存标识发送给服务器,服务器拿到标识后判断标识是否匹配,如果不匹配,表示资源有更新,服务器会将新数据和新的缓存标识一起返回到浏览器;如果缓存标识匹配,表示资源没有更新,并且返回 304 状态码,浏览器就读取本地缓存服务器中的数据。

  • http 1.0 last-Modified

  • Etag

3 强缓存( Cache-Control 和 Expires )

强缓存主要是采用响应头中的 Cache-ControlExpires 两个字段进行控制的。

其中 Expires 是 HTTP1.0 中定义的,它指定了一个绝对的过期时期。而 Cache-Control 是 HTTP1.1 时出现的缓存控制字段。由于 Expires 是 HTTP1.0 时代的产物,因此设计之初就存在着一些缺陷,如果本地时间和服务器时间相差太大,就会导致缓存错乱。

所以当这两个字段同时使用的时候,Cache-Control 的优先级会更高一点。

请求头中使用 Cache-Control 时,它可选的值有:

指令说明
no-cache使用代理服务器的缓存之前提交原始服务器验证,验证通过才能使用
no-store在客户端或是代理服务器都不缓存请求或响应的任何内容
max-age=[秒]告知服务器客户端可接受资源的存在最大时间
max-stale(=[秒])可接受(代理服务器缓存的)过期资源,参数可省略
min-fresh=[秒]可接受(代理服务器缓存的)资源更新时间小于指定时间
no-transform代理服务器不可以更改媒体类型
only-if-cached客户端只接受已缓存的响应,若缓存不命中,则返回 504 错误
cache-extension自定义扩展值,若服务器不知别该指令,就直接忽略

响应头中使用 Cache-Control 时,它可选的值有:

指令说明
public表明该资源可以给多个用户使用
private(= name)该资源是私有资源,指定的用户可以使用的缓存
no-cache强制每次请求直接发送给源服务器,而不经过本地缓存版本的校验。
no-store在客户端或是代理服务器都不缓存请求或响应的任何内容
no-transform代理服务器不可以更改媒体类型
must-revalidate可缓存但必须再向源服务器进行请求确认
proxy-revalidate要求缓存服务器返回缓存的时候向源服务器进行请求确认
max-age=[秒]告知客户端该资源在规定时间内是新鲜的,无需向服务器确认
s-maxage=[秒]告知缓存服务该资源在规定时间内是新鲜的,无需向服务器确认
cache-extension自定义扩展值,若服务器不识别该指令,就直接忽略

可缓存性

  1. public:响应可以被任何对象(客户端、代理服务器等)缓存
  2. private:只能被单个用户缓存,不能作为共享缓存
  3. no-cache:使用缓存副本之前,需要将请求提交给原始服务器进行验证,验证通过才可以使用
  4. only-if-cached:客户端只接受已缓存的响应,并且不向原始服务器检查是否有更新的拷贝

到期

  1. max-age=<seconds>:缓存存储的最大周期,超过这个时间缓存被认为过期(单位秒)。与 Expires 相反,时间是相对于请求的时间
  2. s-maxage=<seconds>:覆盖 max-age 或者 Expires 头,但是仅适用于共享缓存(比如各个代理),并且私有缓存中它被忽略
  3. max-stale[=<seconds>]:表明客户端愿意接收一个已经过期的资源。可选的设置一个时间(单位秒),表示响应不能超过的过时时间
  4. min-fresh=<seconds>:表示客户端希望在指定的时间内获取最新的响应

重新验证和重新加载

  1. must-revalidate:缓存必须在使用之前验证旧资源的状态,并且不可使用过期资源。
  2. proxy-revalidate:与 must-revalidate 作用相同,但它仅适用于共享缓存(例如代理),并被私有缓存忽略

其他

  1. no-store:彻底得禁用缓冲,本地和代理服务器都不缓冲,每次都从服务器获取
  2. no-transform:不得对资源进行转换或转变。 Content-Encoding, Content-Range, Content-TypeHTTP 头不能由代理修改。

4 协商缓存 ( Last-Modified 和 Etag )

协商缓存机制下,浏览器需要向服务器去询问缓存的相关信息,进而判断是重新发起请求还是从本地获取缓存的资源。如果服务端提示缓存资源未改动( Not Modified ),资源会被重定向到浏览器缓存,这种情况下网络请求对应的状态码是 304

Last-Modified 和 If-Modified-Since

都是基于资源在服务器修改时间而验证缓存的过期机制

当客户端再次请求该资源的时候,会在其请求头上附带上If-Modified-Since字段(值为第一次获取请求资源时响应头中返回的Last-Modified 值)。如果修改时间未改变则表明资源未过期,命中缓存,服务器就直接返回 304 状态码,客户端直接使用本地的资源。否则,服务器重新发送响应资源,从而保证资源的有效性。

Etag 和 If-None-Match

基于资源校验码(一般为md5值)而验证缓存的过期机制

当客户端再次请求该资源的时候,会在其请求头上附带上 If-None-Match 字段(值就是第一次获取请求资源时响应头中返回的 Etag 值),其值与服务器端资源文件的验证码进行对比,如果匹配成功直接返回 304 状态码,从浏览器本地缓存取资源文件。如果不匹配,服务器会把新的验证码放在请求头的 Etag 字段中,并且以 200 状态码返回资源。

需要注意的是当响应头中同时存在 EtagLast-Modified 的时候,会先对 Etag 进行比对,随后才是 Last-Modified

为什么既有last-modified又有Etag? 原因如下:

  1. 一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候,我们并不希望客户端认为这个文件被修改了,而重新请求该资源,而Etag是对文件的内容进行hash计算,如果文件内容没有发生改变,Etag也不会发生改变,客户端也不会重新请求该资源

  2. 某些文件修改非常频繁,比如在秒以下的时间内进行修改(比方说 1s 内修改了 N 次),If-Modified-Since能检查到的粒度时 s 级的,这种修改无法判断(或者说 UNIX 记录 MTIME只能精确到秒),这时候客户端可能会得到错误的资源

  3. 某些服务器不能精确得到的文件的最后修改时间

  4. 一般情况下Last-Modified已经足够,ETag只在特定情况下才更有用,有时候前端发布文件不可能一秒发布好多次,而且Etag可能会给服务器带来更大的开销(使用了MD5加密算法),所以一般就用Last-Modified就行,ETag可以看作是对Last-Modified的一个补充

所以利用Etag可以更准确的控制缓存,优先级也更加高。

Etag 的问题

相同的资源,在两台服务器产生的 Etag 是不是相同的,所以对于使用服务器集群来处理请求的网站来说, Etag 的匹配概率会大幅降低。所在在这种情况下,使用 Etag来处理缓存,反而会有更大的开销。

5 静态资源的请求过程

第一次请求肯定是从服务器中请求多来的资源,而第一次的响应头一般包含可强缓存的相关字段cache-control ,同时也包含了协商缓存的相关字段 etaglast-modified;

当强缓存和协商缓存字段同时存在的时候,会按照以下步骤来请求资源

  1. 强缓存优先级 > 协商缓存优先级 强缓存和协商缓存同时存在,如果强缓存还在有效期内则直接使用缓存;如果强缓存不在有效期,协商缓存生效。

  2. cache-control 优先级 > expires优先级 强缓存的 expirescache-control 同时存在时, cache-control 会覆盖 expires 的效果, expires 无论有没有过期,都无效。

  3. ETag优先级 > Last-Modified 优先级。 协商缓存的 EtagLast-Modified 同时存在时, Etag 会覆盖 Last-Modified的效果。

第二次请求该资源的时候,如果命中强缓存,则直接从缓存中读取(from disk cache),否则协商缓存生效

其实我们第一次获取的资源极有可能是从 CDN 节点的缓存中获取的,也很有可能是从中间代理服务器(nginx,node 等)的缓存中读取的;

6 动态资源

由于动态资源的返回结果不一致,所以这个我们肯定不会在浏览器(中间代理服务器)缓存动态的结果。

不过这里我们可以在后端缓存一些重复率比较高的相关的计算结果.

所以关于动态资源一般前端是不做缓存的。

参考文章:从输入 URL 到展现涉及哪些缓存环节(非常详细)

喜欢这篇文章吗?

加载中...

评论

0

登录后即可参与评论讨论

加载评论中...

相关文章

浏览器渲染原理以及海量数据渲染的方法

浏览器的渲染原理 浏览器工作流程:构建 DOM -> 构建 CSSOM -> 构建渲染树 -> 布局 -> 绘制。 1. 首先解析接收到的文档,根据文档定义构建一棵 DOM 树,DOM 树是 DOM 元素及属性节点组成的 2. 然后对 CSS 进行解析,生成 CSSOM 规则树 3. 根据 DOM 树和 CSSOM 规则树构建渲染树,渲染树的节点被称为渲染对象,渲染对象是一个包含有颜色和大小等...

浏览器
浏览器进阶

2025-06-22

2

0

目录