浏览器的强缓存和协商缓存

2021/10/14 javascriptcachebrowser

# 前言

这篇文章我们主要来聊一聊浏览器的两种缓存机制:强缓存和协商缓存。

# 介绍

浏览器缓存分为强缓存与协商缓存两种方式:

  • 强缓存是由 Header 里的 Expires 字段实现的。
  • 协商缓存有两种方式:
    • 使用 Last-ModifiedIf-Modified-Scene 实现。
    • 使用 ETagIf-None-Match 实现。

# 强缓存

强缓存和协商缓存最大的一个区别在于:强缓存在验证请求是否存在缓存时,不需要向服务器发送请求。

当浏览器第一次向服务器发送请求时,服务器返回的返回头里如果设置了强缓存,浏览器会将请求返回内容与返回头一同存到浏览器缓存中。

当浏览器再次请求该改内容时,浏览器会先去缓存中寻找该请求,然后判断返回头里的缓存时间和当前客户端时间判断;如果在这时间之前的话,就直接重缓存中取得内容,F12 打开控制面板查看网络会发现请求显示 from cache

# 如何开启强缓存

Response Header 中使用 ExpiresCache-Control 即可。若二者同时存在,Cache-Control 优先级高于 Expires

# Expires

Expires 描述的是一个绝对时间,由服务器返回,用 GMT 格式的字符串表示,如:Expires:Thu, 31 Dec 2037 23:55:55 GMT

当使用 Expires 时,客户端将当前时间与 Expires 的值作比较,若当前时间晚于 Expires 时间,客户端将重新向服务器发起请求。

# Cache-Control

Cache-Control 是一个相对时间,在配置缓存的时候,以秒为单位,用数值表示,如:Cache-Control:max-age=315360000

当使用 Cache-Control 时,客户端会利用第一次请求时间与 Cache-control 值计算出一个过期时间,如何与客户端当前时间作比较,晚于当前时间,则重新向服务器发送请求。

# 强缓存的缺陷

由于客户端判断是否需要重新请求服务器的时间,是由客户端决定的,所以,若客户端时间与服务器时间不一致时(或用户主动更改了客户端时间),将导致缓存管理混乱,无法实现缓存功能。

# 协商缓存

由于强缓存的缺陷,后来提出了另一种缓存方式,即协商缓存。

协商缓存顾名思义,需要由服务器和客户端共同决定是否使用缓存数据。所以协商缓存不管是否使用缓存数据,都会向服务器发送一条请求。

服务器根据请求头中的 If-Modified-SceneIf-None-Match 来判断是否使用缓存内容。如果匹配成功,F12 打开控制台查看请求会显示 304 状态 Not Modified。浏览器读到返回后去缓存中取得请求内容。如果匹配失败则直接返回新的内容。

Last-ModifiedIf-Modified-Since】和【ETagIf-None-Match】一般都是同时启用,这是为了处理 Last-Modified 不可靠的情况。比如修改了客户端时间或是服务器上资源其实有变化,但是最后修改时间却没有变化的情况。

# Last-Modified 和 If-Modified-Scene

Last-Modified 是一个相对时间,以秒为单位,用数值表示,如:Cache-Control:max-age=315360000

浏览器发送请求时会在请求头中添加 If-Modified-Scene ,值为首次请求返回头中的 Last-Modified。服务器在接收到请求后,会根据服务器上文件最新修改时间和请求头中的 If-Modified-Scene 作比较,确定是返回304 Not Modified 还是新的请求内容。

# ETag 和 If-None-Match

ETag 是一个服务器为该请求资源生成的一个唯一标志。首次请求时由服务器返回。

浏览器再次请求该资源时,会在请求头中添加 If-None-Match。值为首次请求返回头中的 ETag。服务器在接收到请求后,会根据服务器上文件的唯一标志和请求头中的 If-None-Match 作比较,确定是返回304 Not Modified还是新的请求内容。

# 协商缓存的缺陷

分布式系统下,每一台服务器为同一资源生成的唯一标志可能不同。如果请求是随机节点的话,也可能会出现缓存失效的情况。