细说浏览器HTTP缓存

HTTP 缓存分为强缓存和协商缓存。

强缓存依据响应头的 max-age 和 expires 判断有效期,有效期内不发出网络请求,直接200。

协商缓存依据请求头的 if-none-match 和 if-modified-since 发出条件请求,校验通过返回304,失败则返回200更新本地缓存。而这两个首部是取自最近一次相同地址的响应头中的 etag 和 last-modified。

实际请求中会先尝试强缓存再走协商缓存。

当有人问我,什么是 HTTP 缓存? 我可能会脱口而出***** (像上面这样)。那真的是这样吗 🤔

细说浏览器HTTP缓存

HTTP 缓存的本质

『HTTP』是指 HTTP 协议。那么『HTTP 缓存』就是 HTTP 协议关于缓存的规范。当我们试图缓存响应的时候可以参考规范中的范式实现。

通俗点说,比如我一个中文初学者,想要用中文『打招呼』。手里刚好有一本这样的参考书。

打招呼常用语:

  • 吃了没
  • 今天天气挺好的
  • 您的气色真不错

我选择其中一句问候我的朋友。如果朋友的中文不错,他很自然明白了我的意思。而如果朋友也是一个中文初学者,很可能他不明白我在说什么。而如果我们是关系很好的朋友,一句『嘿』就可以完成打招呼。

使用 HTTP 通信的场景不都有 HTTP 缓存,这取决于通信双方对规范的实现情况。 Postman 可以用来发送 HTTP 请求,但是由于其工具性质不实现 HTTP 缓存。而浏览器对 HTTP 缓存的实现比较全面。后文将探究浏览器实现的 HTTP 缓存。

缓存流程

细说浏览器HTTP缓存
一个 <img src="my-image.png"> 产生的网络请求经过各级缓存的顺序也是『洋葱模型』。

  1. 最先经过 service worker 查找缓存。
  2. 接着就是浏览器缓存,强缓存、弱缓存都是这里。
  3. 然后服务端如果使用 CDN 网络,会经过各级 CDN 节点查找缓存。
  4. 最后到达后端服务。

浏览器缓存策略

可配置缓存策略

大部分前端页面产生的 HTTP 访问前端工程师无法控制其应用的缓存策略。有个例外,fetch API 的 cache

// 跳过缓存
fetch('/a.js', {cache: 'no-store'}).then(res => {
});
名称 策略 请求头表现
default 依次尝试强缓存、协商缓存,获取响应后更新缓存 省略 cache-control pragma ,携带if-*首部
no-store 跳过缓存,直接请求服务端,响应不用于更新缓存 省略两个if-* 首部
reload 跳过缓存,直接请求服务端,获取响应后更新缓存 省略两个if-* 首部
no-cache 请求服务端校验协商缓存,获取响应后更新缓存 cache-control: max-age=0 ,携带if-*首部
force-cache 有缓存用缓存,没缓存请求服务更新缓存(无论是否过时) 省略 cache-control pragma ,携带if-*首部
only-if-cached 有缓存用缓存,没有就报错 不会产生请求

此处 no-cache 不能和 cache-control: no-cache 混淆。

no-storereload 在一些浏览器中请求头会带有 cache-control: no-cache。根据 HTTP 缓存关于请求首部规范,cache-control: no-cache 意为 『客户端希望在服务端验证有效的前提下应用缓存』;而 cache-control: max-age=0 意为『客户端应用有效期为0的强缓存,即跳过强缓存』。两者意思相近,而决定no-storereload跳过缓存的是省略两个if-* 首部

默认缓存策略

1. 常规页面访问

场景:文档跳转、地址栏回车、点击刷新按钮、页面右键重新加载、command+R

  • 根文档(html):应用类似 fetch cache no-cache 策略
  • 其他资源(css、js、png…)应用类似 fetch cache default 策略

2. 硬性重新加载

场景:command+shift+R

  • 根文档(html):应用类似 fetch cache no-cache 策略
  • 其他资源(css、js、png…)初次请求应用类似 fetch cache no-cache 策略,重复请求应用default 策略

强缓存

强缓存在 Network 中表现为状态码200且标记为已缓存,直接应用客户端缓存,不发出 HTTP 请求

细说浏览器HTTP缓存
满足以下三个条件可应用强缓存

  • 缓存中的响应头不阻止强缓存:像cache-control: no-cachepragma: no-cache就不行。
  • 当前策略不阻止强缓存:像cache: no-cache和硬性重新加载就不行。
  • 缓存在有效期内:明确的时间或启发式的推断。

关于响应头中的cache-control取值

明确时间的强缓存

1. max-age

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1024
Cache-Control: max-age=5

<!doctype html>

HTTP1.1 规范中的首部 cache-control 取值 max-age=[namber] ,表示当前响应在缓存中有效的时间段

2. Expires

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1024
Expires: Tue, 22 Feb 2022 22:22:22 GMT

<!doctype html>

Expires 是 HTTP1.0 规范的首部,表示当前响应在缓存中过时的时间点

max-age 的优先级高于 Expires 。

启发式缓存

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1024
Date: Tue, 22 Feb 2022 22:22:22 GMT
Last-Modified: Tue, 22 Feb 2021 22:22:22 GMT

<!doctype html>

在缓存的响应没有 Cache-ControlPragmaExpires的时候,浏览器将依据 Last-ModifiedDate 计算一个推断的有效期

有效期=(DateLastModified)n有效期 = (Date – LastModified ) * n

n 是一个0到1的系数,规范建议取0.1。以前面的例子来说,这条缓存距离服务端资源变更已有1年,因此推断它还能使用0.1年,在'Tue, 22 Feb 2022 22:22:22 GMT'+0.1年后过时。

协商缓存

协商缓存将发出带有 if-none-matchif-modified-since 的 HTTP 条件请求,服务端校验缓存是否有效。

  • 如果校验通过,则复用本地缓存,状态码304。
  • 如果校验失败,则返回新的响应,状态码200。
    依据响应头中的cache-control取值是否更新缓存。

细说浏览器HTTP缓存
请求头中有两个 if-* 之一是协商缓存的必要条件。由于缓存中没有对应的特征首部(last-modified和etag)或者前文缓存策略导致省略两个 if-*都不能完成协商缓存。

if-none-match

GET /a HTTP/1.1
Host: localhost:3000
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate, br
If-None-Match: 123

if-none-match 在 HTTP1.1 规范中意为 『如果没有命中该值则需要服务端处理』 。抛开缓存策略的影响,if-none-match 通常取自缓存响应头的 etag ,是响应的特征串(响应体长度、hash或者叠加运算)。

if-modified-since

GET /a HTTP/1.1
Host: localhost:3000
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate, br
If-Modified-Since: Tue, 22 Feb 2022 22:22:22 GMT

if-modified-since 在 HTTP1.1 规范中意为 『如果在改时间点后发生了变更则需要服务端处理』 。抛开缓存策略的影响,if-modified-since 通常取自缓存响应头的 last-modified ,是响应资源的最近修改时间。

浏览器缓存流程

细说浏览器HTTP缓存

这里省略了强缓存和协商缓存的细节,不过经过上面的解释还有您的长期积累相信可以补充出来。

以上也只是本人看规范、写 demo、对比几家之言,得到的一点总结,欢迎讨论指正。

延伸阅读

原文链接:https://juejin.cn/post/7236670795061329977 作者:蓝色夜晚

(0)
上一篇 2023年5月25日 上午10:49
下一篇 2023年5月25日 上午11:02

相关推荐

发表回复

登录后才能评论