浏览器缓存

前端优化:浏览器缓存技术介绍
浅谈浏览器http的缓存机制
Http协议缓存了解一下

一个优秀的缓存策略可以缩短网页请求资源的距离,减少延迟,并且由于缓存文件可以重复利用,还可以减少带宽,降低网络负荷。所以,缓存技术是无数WEB开发从业人员在工作过程中不可避免的一大问题。

第一次打开该网站后,如果再次刷新页面。会发现浏览器加载的众多资源中,有一部分size有具体数值,然而还有一部分请求,比如图片、cssjs 等文件并没有显示文件大小,而是显示了from disk cache 或者from memory cache字样。这就说明了,该资源直接从本地硬盘或者浏览器内存读取,而并没有请求服务器。

HTTP与缓存

浏览器是否使用缓存、缓存多久,是由服务器控制的。准确来说,当浏览器请求一个网页(或者其他资源)时,服务器发回的响应的响应头部分的某些字段指明了有关缓存的关键信息。下面看下,http报文中与缓存相关的首部字段:

通用首部字段

字段名称 说明
Cache-Control 控制缓存的行为
Pragma http1.0遗留的产物,当值为no-cache 时候禁止使用缓存

请求首部字段

字段名称 说明
if-Match 比较 Etag 是否一致 (EtagURLEntity Tag,用于标示URL对象是否改变,区分不同语言和Session等等。)
if-None-Match 比较 Etag是否不一致
if-Modified-Since 比较资源最后更新的时间是否一致
if-Unmodified-Since 比较资源最后更新的时间是否不一致

响应首部字段

字段名称 说明
ETag 资源匹配的信息

实体首部的字段

字段名称 说明
Expires http1.0,实体主体过期的时间
Last-Modified 资源最后一次修改的时间

缓存的判断规则

过期机制

过期机制就是浏览器根据缓存的有效期进行判断,如果在有效期内就使用缓存,否则就抛弃这个缓存。

一个缓存副本必须满足以下条件,浏览器会认为它是有效的,足够新的:

  • 含有完整的过期时间控制头信息(http协议报头),并且仍在有效期内;
  • 浏览器已经使用过这个缓存副本,并且在一个会话中已经检查过新鲜度。

验证机制

浏览器带上本地缓存副本的验证信息提交给服务器(Last-Modified,ETag),由服务器决定是否采用这个缓存。

客户端请求的时候带上Last-Modified,服务器进行验证返回If-Modified-Since来确定资源是否是有效缓存。 另外在控制头信息带上这个资源的实体标签EtagEntity Tag),它可以用来作为浏览器再次请求过程的校验标识。如过发现校验标识不匹配,说明资源已经被修改或过期,浏览器需求重新获取资源内容。

缓存来源

from disk cache

此资源是从磁盘当中取出的,也是在已经在之前的某个时间加载过该资源,不会请求服务器但是此资源不会随着该页面的关闭而释放掉,因为是存在硬盘当中的,下次打开仍会from disk cache

from memory cache

字面理解是从内存中,其实也是字面的含义,这个资源是直接从内存中拿到的,不会请求服务器一般已经加载过该资源且缓存在了内存当中,当关闭该页面时,此资源就被内存释放掉了,再次重新打开相同页面时不会出现from memory cache的情况。

强缓存和协商缓存

浏览器在加载缓存的时候,会先根据这个资源的一些 http header 判断它是否命中强缓存。如果命中的话,浏览器直接从自己的缓存中读取资源,不会发送请求给服务器。比如:某个css文件,如果浏览器在加载它所在的网页时,这个css文件的缓存配置命中了强缓存,浏览器就直接从缓存中加载这个css,连请求都不会发送到网页所在服务器;

当强缓存没有命中的时候,浏览器一定会发送一个请求到服务器,通过服务器端依据资源的另外以一些 http header验证这个资源是否命中协商缓存,如果命中协商缓存,服务器会将这个请求返回,但是不会返回这个资源的数据,而是告诉客户端直接从缓存中加载这个资源,于是浏览器就会又去从自己的缓存中去加载资源

强缓存与协商缓存的共同点是:如果命中,都是从客户端缓存中加载资源,而不是从服务器加载资源数据;区别是:强缓存不发请求到服务器,协商缓存会发请求到服务器。

强缓存

当某个浏览器请求的某个资源命中强缓存的时候,返回的http状态码是200,在chrome的开发者工具的network里面 size会显示为from disk cache

强缓存是利用Expires或者Cache-Control这两个http response header实现的,它们都用来表示资源在客户端缓存的有效期。

Expires

ExpiresHTTP 1.0提出的一个表示资源过期时间的header,它描述的是一个绝对时间,由服务器返回,用GMT格式的字符串表示,如:Expires:Thu, 31 Dec 2037 23:55:55 GMT,包含了Expires头标签的文件,就说明浏览器对于该文件缓存具有非常大的控制权。

例如,一个文件的Expires值是2020年的1月1日,那么就代表,在2020年1月1日之前,浏览器都可以直接使用该文件的本地缓存文件,而不必去服务器再次请求该文件,哪怕服务器文件发生了变化。

所以,Expires是优化中最理想的情况,因为它根本不会产生请求,所以后端也就无需考虑查询快慢

Expires是较老的强缓存管理header,由于它是服务器返回的一个绝对时间,在服务器时间与客户端时间相差较大时,缓存管理容易出现问题,比如:随意修改下客户端时间,就能影响缓存命中的结果

所以在HTTP 1.1的时候,提出了一个新的header,就是Cache-Control

Cache-Control

Cache-Control描述的是一个相对时间,在进行缓存命中的时候,都是利用客户端时间进行判断,所以相比较ExpiresCache-Control的缓存管理更有效,安全一些。

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

此外,还可以为Cache-Control指定 publicprivate 标记。如果使用private,则表示该资源仅仅属于发出请求的最终用户,这将禁止中间服务器(如代理服务器)缓存此类资源。对于包含用户个人信息的文件(如一个包含用户名的 HTML 文档),可以设置private,一方面由于这些缓存对其他用户来说没有任何意义,另一方面用户可能不希望相关文件储存在不受信任的服务器上。

需要指出的是,private 并不会使得缓存更加安全,它同样会传给中间服务器(如果网站对于传输的安全性要求很高,应该使用传输层安全措施)。

对于public,则允许所有服务器缓存该资源。通常情况下,对于所有人都可以访问的资源(例如网站的 logo、图片、脚本等),Cache-Control 默认设为 public是合理的。

Cache-Control优先级高于Expires
  • 这两个header可以只启用一个,也可以同时启用,当response header中,ExpiresCache-Control同时存在时,Cache-Control优先级高于Expires
  • Cache-Control描述的是一个相对时间,在进行缓存命中的时候,都是利用客户端时间进行判断,所以相比较ExpiresCache-Control的缓存管理更有效,安全一些。
  • 这两个header可以只启用一个,也可以同时启用,当response header中,ExpiresCache-Control同时存在时,Cache-Control 优先级高于Expires

协商缓存

当浏览器对某个资源的请求没有命中强缓存,就会发一个请求到服务器,验证协商缓存是否命中,如果协商缓存命中,请求响应返回的http状态为304并且会显示一个Not Modified的字符串,比如你打开京东的首页,按 f12 打开开发者工具,再按 f5 刷新页面,查看 network,可以看到有不少请求就是命中了协商缓存的。

Last-Modified If-Modified-Since

浏览器第一次跟服务器请求一个资源,服务器在返回这个资源的同时,在responseheader加上Last-Modifiedheader,这个header表示这个资源在服务器上的最后修改时间

浏览器再次跟服务器请求这个资源时,在requestheader上加上If-Modified-Sinceheader,这个header的值就是上一次请求时返回的Last-Modified的值

根据浏览器传过来If-Modified-Since和资源在服务器上的最后修改时间判断资源是否有变化,如果没有变化则返回304 Not Modified,但是不会返回资源内容;如果有变化,就正常返回资源内容。当服务器返回304 Not Modified的响应时,response header 中不会再添加 Last-Modified 的 header,因为既然资源没有变化,那么 Last-Modified 也就不会改变

浏览器收到304的响应后,就会从缓存中加载资源;

如果协商缓存没有命中,浏览器直接从服务器加载资源时,Last-Modified Header在重新加载的时候会被更新,下次请求时,If-Modified-Since会启用上次返回的Last-Modified值。

Etag

【Last-Modified,If-Modified-Since】都是根据服务器时间返回的header,一般来说,在没有调整服务器时间和篡改客户端缓存的情况下,这两个header配合起来管理协商缓存是非常可靠的。

但是有时候也会服务器上资源其实有变化,但是最后修改时间却没有变化的情况,而这种问题又很不容易被定位出来,而当这种情况出现的时候,就会影响协商缓存的可靠性

所以就有了另外一对header来管理协商缓存,这对header就是ETagIf-None-Match。它们的缓存管理的方式是:

Etag 的工作原理

浏览器第一次跟服务器请求一个资源,服务器在返回这个资源的同时,在responseheader加上ETagheader,这个header是服务器根据当前请求的资源生成的一个唯一标识,这个唯一标识是一个字符串,只要资源有变化这个串就不同,跟最后修改时间没有关系,所以能很好的补充Last-Modified的问题;

浏览器再次跟服务器请求这个资源时,在requestheader上加上If-None-Matchheader,这个header的值就是上一次请求时返回的ETag的值;

服务器再次收到资源请求时,根据浏览器传过来If-None-Match和然后再根据资源生成一个新的ETag,如果这两个值相同就说明资源没有变化,否则就是有变化;如果没有变化则返回304 Not Modified,但是不会返回资源内容。

如果有变化,就正常返回资源内容。与Last-Modified不一样的是,当服务器返回304 Not Modified的响应时,由于ETag重新生成过,response header中还会把这个ETag返回,即使这个ETag跟之前的没有变化;

浏览器收到304的响应后,就会从缓存中加载资源。

Etag 和 Last-Modified

EtagLast-Modified非常相似,都是用来判断一个参数,从而决定是否启用缓存。但是ETag相对于Last-Modified也有其优势,可以更加准确的判断文件内容是否被修改,从而在实际操作中实用程度也更高。

协商缓存跟强缓存不一样,强缓存不发请求到服务器,所以有时候资源更新了浏览器还不知道,但是协商缓存会发请求到服务器,所以资源是否更新,服务器肯定知道。大部分 web 服务器都默认开启协商缓存,而且是同时启用 Last-Modified,If-Modified-Since 和 ETag、If-None-Match

如果没有协商缓存,每个到服务器的请求,就都得返回资源内容,这样服务器的性能会极差。

Last-ModifiedIf-Modified-SinceETagIf-None-Match一般都是同时启用,这是为了处理Last-Modified不可靠的情况。有一种场景需要注意:

协商缓存需要配合强缓存使用,Last-Modified这个header,还有强缓存的相关header,因为如果不启用强缓存的话,协商缓存根本没有意义。

你可能感兴趣的:(浏览器缓存)