HTTP的场景实践 | 青训营

60 阅读5分钟

  之前对于HTTP协议的理解还是比较浅薄,打算趁热打铁写一篇关于缓存策略分析的实践笔记。

PS: 本文章是基于MDN 《HTTP 缓存》文章的论点进行学习总结,并对哔哩哔哩动画网站的网络请求协议中缓存策略进行分析学习。

1. HTTP 缓存的好处

  HTTP 缓存是指存储请求相关的响应,提高响应内容的可复用性。正确地使用缓存,不仅能降低服务器的负载,还能提升请求响应速度,改善用户使用体验。

2. HTTP 缓存分类

  在 HTTP Caching 标准中,有两种不同类型的缓存:私有缓存和共享缓存。

1. 私有缓存

  私有缓存是绑定到特定客户端的缓存——通常是浏览器缓存。私有缓存的数据不会和其他用户共享,信息的安全性高,不容易泄露,因此一般用来存储用户的个性化响应。

  使用私有缓存策略需要在在响应头中通过以下方法设置:

Cache-Control: private

2. 共享缓存

  共享缓存位于客户端和服务器之间,可以存储能在用户之间共享的响应。共享缓存可以进一步细分为代理缓存和托管缓存。

  • 代理缓存

  在客户端和服务端之间设置代理服务器并使用代理缓存可以减轻后端服务器的负载,减少网络流量,提高网站并发量,提升用户体验度。近年来,随着 HTTPS 变得越来越普遍,客户端/服务器通信变得加密,在许多情况下,路径中的代理缓存只能传输响应而不能充当缓存。这种情况下早年间由于代理缓存的存在而产生的代理缓存“已过时且未更新”问题自然迎刃而解了。

  • 托管缓存

  托管缓存由服务开发人员明确部署,以降低源服务器负载并有效地交付内容,例如反向代理、CDN 和 service worker 与缓存 API 的组合。

3. 启发式缓存

  除了给定Cache-Control 标头而设置的缓存策略,HTTP 协议也存在一些自定的缓存策略。为了尽可能多地缓存,在源服务器响应没有给出 Cache-Control 的前提下,如果满足某些条件,响应也会被存储和重用,这称为“启发式缓存”。

4. 关于缓存

缓存状态

  响应的缓存资源存在fresh(有效资源)和state(过期资源)两种状态。http根据自响应生成以来经过的时间 age 来判别缓存状态。

  关于 Cache-Control 标头的 max-age 和 判定缓存状态的age,我认为max-age是基于请求响应后得到的缓存策略中设置的该响应缓存有效的最大周期(即可直接使用的有效期)而age是相对于请求响应后获取到该响应之后度过的时间。

  age的缓存状态检测主要作用在过了一段时间后,共享缓存向客户端请求发送携带age响应。根据max-age和age可以计算出剩余多少时间是缓存可用有效的。而只要存储的响应保持有效(fresh),存储的缓存将用于兑现客户端请求。

 

缓存有效期

  缓存在有效期之内时,缓存的资源才是有效可用的。而标识缓存有效期的字段是 Expired 和 max-age;

   在HTTP/1.0 中,有效期是通过 Expires 标头来指定的。但由于Expired指定的有效期是某个具体的时间,而这个时间容易收到系统时钟的影响而产生有效期判定偏差。因此在HTTP/1.1中,有效期通过max-age指定。max-age指定的是从响应开始的缓存有效期,是指经过时间。

  虽然HTTP/1.1已经成为了被广泛应用的协议版本,但有时候开发人员为了兼容HTTP/1.0的设置会同时设置Expired和Cache-control中的max-age声明,当两者均有效的时候,优先采用max-age来进行有效期计算。

缓存策略

  常见的缓存策略包括强缓存和协商缓存两种类型。具体内容介绍可见前文:juejin.cn/post/727082…

  接下来将针对哔哩哔哩动画首页的网络请求进行缓存策略分析。

  首先,对于内容变化性大、不适合缓存的html文件的请求内响应部分的内容如下:

  Cache-Control 标头内只包含了 no-cache字段,说明了该请求得到的响应里缓存设置被指定成”强制验证“。每当客户端访问该资源,请求就会被发往服务端进行缓存响应有效性的验证,如果响应有效,客户端可以直接读取缓存加载。

  下图中显示了,该首页是通过跟服务端交互获得响应资源,并不是通过缓存获取的。

  第二,关于内容不经常变化,比较适合缓存的静态资源,例如下列JS资源的请求响应如下:

  缓存规则内设置了响应有效期是一年,即在请求响应缓存后该缓存资源一年内有效。

  在下图可以看到,因为该资源仍处于有效期内,因此资源的请求响应源自强缓存的响应缓存,虽然没有和源服务器进行交互但也获取到了响应资源。

  • 缓存破坏

  虽然在有效期内js代码可能会变化,而该缓存响应也变得不可使用,但缓存的静态资源也能通过别的方式重新链接。这种方式被称为“缓存破坏”,即每次静态资源内容变化时都改变请求该资源的URL。

  通常开发时会使用包含基于版本号或哈希值的更改部分的 URL 来提供 JavaScript 和 CSS(如下图),这样保证了在更新资源时 URL 发生变化,缓存将不会再次被重用。