一篇文章解释清楚浏览器缓存

301 阅读5分钟

什么是浏览器缓存,缓存的作用是什么

就是将某一次请求的资源缓存在浏览器,以供后续请求直接使用,通过浏览器缓存,可以大大减少网络传输量和服务器压力,同时,使用缓存的情况下可以大大的加快资源的响应速度。我们以掘金首页为例子,可以看看network中很多资源都直接从缓存中读取,请求时间为0ms

p1.png

如何实现缓存,缓存的规则是什么

要想实现资源缓存,主要由服务器返回的响应头控制。还是以掘金首页为例,我们刷新并清空缓存,任意点进一个静态资源的请求中,可以看到服务器返回的响应头中包含如下信息

p2.png

  • Cache-Control :Max-age = 31536000 该资源缓存31536000毫秒
  • Date: 该资源返回时间为 Thu, 09 May 2024 02:04:35 GMT
  • ETag : http1.1提供 ,该资源的唯一标识是W/"3be5f29ac3de039909660e93e1ca5912"
  • Last-Modified: http1.0提供, 该资源上次修改时间是 Sun, 28 Apr 2024 07:55:34 GMT

当浏览器收到这些信息时,会将资源缓存和缓存信息存到本地,这样就实现了浏览器缓存。

当下一次访问这个资源时,会根据请求方法请求路径,优先查看缓存列表。如果浏览器发现有缓存,会经过以下流程

检查资源是否有效

检查的方式也很简单,通过max-age+Date计算出过期时间,如果过期时间大于当前时间,则缓存仍然有效,如果过期时间小于当前时间,则说明该资源已经过期

缓存有效

当浏览器发现缓存有效时,浏览器不会讲本次请求发送,会直接使用本地缓存,请求返回200,会大大降低服务器的压力。然而在这种情况下,当资源内容发生变化时,浏览器并不会重新请求,还是会使用缓存的结果。这就是常说的强缓存

缓存过期

当浏览器发现缓存已经过期,这时候也并不会直接请求服务器去拿新的资源,而是向服务器发送一个带缓存信息的请求,询问服务器资源有没有发生变化。请求头中会包含下图中两个字段

  • if-Modified-Since: 这个值来自于之前缓存该资源时的Last-Modified字段,询问服务器这个资源自这个时间之后有没有发生变化
  • if-None-Match: 这个值来自于缓存该资源时的Etag字段,用于询问该资源的资源编号有没有发生变化

这两个字段的主要作用都是询问服务器,资源有没有发生变化 (浏览器的缓存是否还是有效的) ,因此又会产生两种情况

缓存有效

如果服务器发现资源并没有发生变化,即浏览器缓存的资源仍然可用,服务器就会返回304响应码,且没有响应体,并且该响应的响应头中还会携带新的缓存信息,Cache-Control 、Date、ETag和Last-Modified,浏览器会继续使用缓存,并且更新缓存信息

缓存失效

如果服务器发现资源已经发生变化,会正常响应浏览器200状态码,响应体中携带新的资源,并且响应头中也会携带新的缓存信息,以便后续请求使用。浏览器发现缓存失效,发送携带缓存信息的请求这个过程,就是常说的协商缓存

强缓存和协商缓存

通俗点讲,强缓存就是服务器通过max-age控制缓存的过期时间,如果在过期时间内,发送的请求都不会抵达服务器,浏览器直接使用缓存。而协商缓存就是每次请求时都去服务器询问,该缓存是否可用,以确保使用的资源是最新的。

额外补充

Cache-Control

在上文提到,Cache-Control可以设置max-age实现强缓存,如果不想让资源强缓存,还可以设置其他值:

  • no-store: 告诉浏览器不对该资源进行缓存,每次请求都向服务器进行正常请求
  • no-cache:告知浏览器缓存该资源,但是每次重新请求该资源时都不要直接使用,而是向服务器发送携带缓存信息的请求 (协商缓存)
  • max-age :设置为0的作用和no-cache的作用一样

有时候我们会发现,请求头中也会出现Cache-Control这个字段,如下图

p5.png 当,Cache-Control:no-cache出现在请求头中,则表示让服务器不用考虑缓存,直接当作正常请求处理

Pragma在此处的作用和Cache-Control一样,Pragma是http1.0的字段

Expire

在http 1.0版本中,通过Expire字段指定缓存过期时间,例如

Expire: Thu, 30 Apr 2024 20:28:18 GMT

到了http 1.1版本,使用Cache-Controlmax-age 来控制

Vary

有时候是否使用缓存除了根据请求方法和请求路径去命中缓存,我们也想通过请求头中的其他字段来确认是否使用缓存,这时候就可以设置Vary字段

例如我们想实现当请求的cookie发生变化时,不使用之前的缓存,可以这样设置

Vary:Cookie

这时候当cookie发生变化无法命中缓存,则浏览器会正常的发送请求