【计算机网络】HTTP 缓存

在一个C/S结构中,最基本的缓存分为两种:

  • 客户端缓存
  • 服务器缓存

以下重点讲客户端缓存

所谓客户端缓存,顾名思义,是将某一次的响应结果保存在客户端(比如浏览器)中,而后续的请求仅需要从缓存中读取即可,极大的降低了服务器的处理乐力。

来自服务器的缓存指令

当客户端发出一个get请求到服务器,服务器希望客户端将相应资源缓存起来,服务器在响应头中加入了以下内容:

Cache-Control:max-age=3600
ETag:W/"121-171ca289ebf"
Date:Thu,30 Apr 2020 12:39:56 GMT
Last-Modified:Thu, 30Apr2o20 08:16:31GMT

这个响应头表达了下面的信息:

  • Cache-Control:max-age=3600, 缓存时间是3600秒(1小时)
  • ETag:W/“121-171ca289ebf”, 这个资源的编号是W/“121-171ca289ebf”
  • Date:Thu,30Apr202012:39:56GMT, 我给你响应这个资源的服务器时间是格林威治时间2020-04-3012:39:56
  • Last-Modified:Thu,30Apr2020g8:16:31GMT, 这个资源的上一次修改时间是格林威治时间2020-04-3088:16:31

如果客户端是其他应用程序,可能并不会理会服务器的愿望,也就是说,可能根本不会缓存任何东西。

如果刚好是一个浏览器,那么就会执行缓存:

  • 浏览器把这次请求得到的响应体缓存到本地文件中
  • 浏览器标记这次请求的请求方法和请求路径
  • 浏览器标记这次缓存的时间是3600秒
  • 浏览器记录服务器的响应时间是格林威治时间2020-04-3012:39:56
  • 浏览器记录服务器给予的资源编号W/“121-171ca289ebf”
  • 浏览器记录资源的上一次修改时间是格林威治时间2020-04-3088:16:31

来自客户端的缓存协议

当客户端准备再次请求GET /index.js时,它突然想起了一件事:我需要的东西在不在缓存里呢?
此时,客户端会到缓存中去寻找是否有缓存的资源
寻找的过程如下:

  1. 缓存中是否有匹配的请求方法和路径?
  2. 如果有,该缓存资源是否有效呢?

以上两个验证会导致浏览器产生不同的行为

image.png

缓存无效(协商缓存)

当浏览器发现缓存已经过期,它并不会简单的把缓存删除,而是抱着一丝希望,想问问服务器,我这个缓存还能继续使用吗?

于是,浏览器向服务器发出了一个带缓存的请求,又称之为协商缓存。

所谓带缓存的请求,无非就是加入了以下的请求头:

If-Modified-Since: Thu,30 Apr 2020 08:16:31 GMT
If-None-Match: W/"121-171ca289ebf"

它们表达了下面的信息:

  • If-Modified-Since:Thu,30Apr202088:16:31GMT 这个资源
    的上一次修改时间是格林威治时间2020-04-3088:16:31,请问这个资源在这个时间之后有
    发生变动吗?
  • If-None-Match:W/“121-171ca289ebf” 这个资源的编号是W/"121
    171ca289ebf, 请问这个资源的编号发生变动了吗?

其实,这两个问题可以合并为一个问题:就是问服务器资源到底变化了没有!

之所以要发两个信息,是为了兼容不同的服务器,因为有些服务器只认If-Modified-Since,有
些服务器只认If-None-Match(优先级更高),有些服务器两个都认。

服务器可能会产生两个情况:

  • 缓存已经失效
  • 缓存仍然有效

如果是第一种情况一一缓存已经失效,那么非常简单,服务器再次给予一个正常的响应(响应码 200 带响应体),同时可以附带上新的缓存指令,这就回到了上一节一一来自服务器的缓存指令。

这样一来,客户端就会重新缓存新的内容。

但如果服务器觉得缓存仍然有效,它可以通过一种极其简单的方式告诉客户端:

  • 响应码为 304 Not Modified
  • 无响应体
  • 响应头带上新的缓存指令,见上一节一一来自服务器的缓存指令

这样一来,就相当于告诉客户端:「你的缓存资源仍然可用,我给你一个新的缓存时间,你那边更新一下就可以了」

于是,客户端就继续使用缓存了。

这样一来,可以最大程度的减少网络传输,因为如果资源还有效,服务器就不会传输消息体

细节

Cache-Control

Cache-Control 是服务器向客户端响应的一个消息头,它提供了一个 max-age 用于指定缓存时间。

实际上,Cache-Control还可以设置下面一个或多个值:

  • public:指示服务器资源是公开的。比如有一个页面资源,所有人看到的都是一样的。这个值对于浏览器而言没有什么意义,但可能在某些场景可能有用。本着「我告知,你随意」的原则,http 协议中很多时候都是客户端或服务器告诉另一端详细的信息,至于另一端用不用,完全看它自己。
  • private:指示服务器资源是私有的。比如有一个页面资源,每个用户看到的都不一样。这个值对于浏览器而言没有什么意义,但可能在某些场景可能有用。本着「我告知,你随意」的原则,http 协议中很多时候都是客户端或服务器告诉另一端详细的信息,至于另一端用不用,完全看它自己。
  • no-cache: 告知客户端,你可以缓存这个资源,但是不要直接使用它。当你缓存之后,后续的每一次请求都需要附带缓存指令,让服务器告诉你这个资源有没有过期。
  • no-store: 告知客户端,不要对这个资源做任何的缓存,之后的每一次请求都按照正常的普通请求进行。若设置了这个值,浏览器将不会对该资源做出任何的缓存处理。
  • max-age: 需要缓存的时间

Expires

http1.1 使用 Expires 来指定过期时间。

记录缓存时的有效期

浏览器会按照服务器响应头的要求,自动记录缓存到本地文件,并设置各种相关信息。

在这些信息中,有效期尤为关键,它决定了这个缓存可以使用多久。

浏览器会根据服务器不同的响应情况,设置不同的有效期。

具体的有效期设置,按照下面的流程进行:

image.png

Pragma

这是 http1.0 版本的消息头。

当该消息头出现在请求中时,是向服务器表达:不要考虑任何缓存,给我一个正常的结果。

在http1.1版本中,可以在请求头中加入Cache-Control:no-cache实现同样的含义。

在Chrome浏览器中调试时,如果勾选了Disable cache,则发送的请求中会附带该信息。

Vary

有的时候,是否有缓存,不仅仅是判断请求方法和请求路径是否匹配,可能还要判断头部信息是否匹配。

此时,就可以使用Vary字段来指定要区分的消息头。比如,当使用GET /personal.html请求服务器时,请求头中cookie的值不一样,得到的页面也不一样。

如果还按照之前的做法,仅仅匹配请求方法和请求路径,如果 cookie 变动,你可能得到的仍然是之前的页面。

使用版本号或hash

当我们打包的结果中很多文件名,类似于这样:app.68297cd8.css

文件的中间部分使用了hash值。

这样做的好处是,可以让客户端大胆的、长时间的缓存该文件,减轻服务器的压力。

当文件改动后,它的文件hash值也会随之而变,比如变成了app.446fccb8.css。

这样一来,客户端要请求新的文件时,就会发现路径从/app.68297cd8.css变成了/app.446fccb8.css, 由于之前的缓存路径无法匹配到,因此就会发送新的请求来获取新资源了。以上是现代流行的做法。

而在古老的年代,还没有构建工具出现时,人们使用的办法是在资源路径后面加入版本号来获取新版本的文件。文件改变,需要手动改变路径。

总结

服务端:

image.png

客户端:

image.png

HTTP 缓存可以通过以下⼏种⽅式进⾏实现:

  1. 浏览器缓存:浏览器可以将最近请求过的资源保存到本地,下次请求时可以直接从本地读取,从⽽提⾼访问速度。
  2. 代理缓存:代理服务器可以缓存响应,减少对原始服务器的请求次数,从⽽加快响应速度。
  3. ⽹关缓存:⽹关可以缓存来⾃多个原始服务器的响应,然后将响应发送到客户端,从⽽提⾼性能。

HTTP 缓存可以分为协商缓存和强制缓存两种类型:

强制缓存是指浏览器在请求资源时,不会发送任何请求头,直接从本地缓存中读取资源,从⽽提⾼响应速度。常⻅的实现⽅式包括:

  1. Expires 头部:指定资源过期的时间,如果在过期时间之前再次请求该资源,浏览器将直接从缓存中读取资源。
  2. Cache-Control 头部:可以指定资源的缓存策略,包括 public、private、no-cache 等,控制浏览器的缓存⾏为。

协商缓存是指浏览器在请求资源时,会发送⼀些请求头到服务器,询问服务器资源是否已经发⽣改变。如果资源未发⽣改变,服务器将返回 304 状态码,告诉浏览器可以从缓存中读取资源,从⽽减少了⽹络带宽的使⽤。常⻅的实现⽅式包括:

  1. Last-Modified / If-Modified-Since 头部:浏览器在请求资源时,会将资源最后修改时间(Last-Modified)发送到服务器,服务器检查资源是否发⽣变化,如果没有发⽣变化,返回 304 状态码,否则返回新的资源。
  2. ETag / If-None-Match 头部:服务器可以给每个资源分配⼀个唯⼀的标识符(ETag),浏览器在请求资源时,将该标识符发送到服务器,服务器检查资源是否发⽣变化,如果没有发⽣变化,返回 304 状态码,否则返回新的资源。

需要注意的是,协商缓存虽然可以减少⽹络带宽的使⽤,但是需要服务器进⾏资源⽐较,因此会增加服务器的负载。

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小秀_heo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值