HTTP缓存

http缓存概念

http缓存指的是: 当客户端向服务器请求资源时,会先抵达浏览器缓存,如果浏览器有“要请求资源”的副本,就可以直接从浏览器缓存中提取而不是从原始服务器中提取这个资源(是否使用缓存还需其他策略进行验证)。

常见的http缓存只能缓存get请求响应的资源,对于其他类型的响应则无能为力,所以后续说的请求缓存都是指GET请求。

http缓存都是从第二次请求开始的。第一次请求资源时,服务器返回资源,并在respone header头中回传资源的缓存参数;第二次请求时,浏览器判断这些请求参数,命中强缓存就直接200,否则就把请求参数加到request header头中传给服务器,看是否命中协商缓存,命中则返回304,否则服务器会返回新的资源。

http缓存的分类

强缓存

定义

强制缓存在缓存数据未失效的情况下(即Cache-Control的max-age没有过期或者Expires的缓存时间没有过期),那么就会直接使用浏览器的缓存数据,不会再向服务器发送任何请求。强制缓存生效时,http状态码为200。

优缺点

优点

  • 直接使用本地缓存,不发送请求,因此响应速度快

缺点

  • 可能无法及时更新服务器资源,造成站点资源的滞后更新

header字段

强缓存是通过http返回头部重的Expires或者Cache-Control两个字段来控制的。

Expires

该字段会返回一个绝对时间,表示该资源的失效时间,在这个时间之前,都可以直接使用缓存,即命中缓存。

Expires

比如上面的图即表示在2021年3月11日03:28:54之前该缓存都有效,即服务器可以使用强缓存,不再请求服务器。

但是这样的绝对时间也会存在问题,即浏览器在校验时间的时候,是根据client的本地时间来确定的,当本地时间与服务器差距较大时,可能存在问题。所以衍生了Cache-Control

Cache-Control

由于上面的问题,Cache-Control返回的就是一个相对时间,以秒为单位。由于是相对时间,并且开始就是和客户端时间相比的,所以即使客户端与服务端时间存在误差,也不会存在误差问题。

其可以是键值对或者一个单值:

单值是一个数字,如:Cache-Control:3600,代表缓存的有效期为3600s。

键值对包含以下属性:

  1. max-age 指定一个时间长度,在这个时间段内缓存是有效的,单位是s。例如设置 Cache-Control:max-age=31536000,也就是说缓存有效期为(31536000 / 24 / 60 * 60)天,第一次访问这个资源的时候,服务器端也返回了 Expires 字段,并且过期时间是一年后。

  2. s-maxage 同 max-age,覆盖 max-age、Expires,但仅适用于共享缓存,在私有缓存中被忽略。

  3. public 表明响应可以被任何对象(发送请求的客户端、代理服务器等等)缓存。

  4. private 表明响应只能被单个用户(可能是操作系统用户、浏览器用户)缓存,是非共享的,不能被代理服务器缓存。

  5. no-cache 强制所有缓存了该响应的用户,在使用已缓存的数据前,发送带验证器的请求到服务器。不是字面意思上的不缓存。

  6. no-store 禁止缓存,每次请求都要向服务器重新获取数据。

  7. must-revalidate指定如果页面是过期的,则去服务器进行获取。这个指令并不常用,就不做过多的讨论了。

cache-control

比如上面的Cache-Controlmax-controlmax-age=600,即600s,10mins的有效期

协商缓存

(当强缓存不满足的时候)协商缓存即还需要向服务器发送一个请求,根据服务器的返回消息来决定是否使用缓存。即如果命中,则http返回304,浏览器从缓存中加载资源。其是根据返回信息的HTTP头部的Last-Modify/If-Modify-Since或Etag/If-None-Match来决定是否命中协商缓存。

优缺点

优点

  • 时效性更高,根据服务器的返回消息决定是否使用缓存。

缺点

  • 载入速度相对会降低,因为会向服务器发送请求。

header字段

Last-Modify/If-Modify-Since

浏览器第一次请求一个资源的时候,服务器返回的header中会加上Last-Modify,Last-modify是一个时间标识该资源的最后修改时间,例如Last-Modify: Thu,31 Dec 2037 23:59:59 GMT。

Last-Modify

当浏览器再次请求该资源时,发送的请求头中会包含If-Modify-Since,该值为缓存之前返回的Last-Modify。服务器收到If-Modify-Since后,根据资源的最后修改时间判断是否命中缓存。

If-Modify-Since

如果命中缓存,则返回http304,并且不会返回资源内容,并且不会返回Last-Modify。由于对比的服务端时间,所以客户端与服务端时间差距不会导致问题。但是有时候通过最后修改时间来判断资源是否修改还是不太准确(资源变化了最后修改时间也可以一致)。于是出现了ETag/If-None-Match。

ETag/If-None-Match

与Last-Modify/If-Modify-Since不同的是,Etag/If-None-Match返回的是一个校验码(ETag: entity tag)。ETag可以保证每一个资源是唯一的,资源变化都会导致ETag变化。ETag值的变更则说明资源状态已经被修改。服务器根据浏览器上发送的If-None-Match值来判断是否命中缓存。

ETag

ETag生成因子

以Apache为例,ETag生成靠以下几种因子

  1. 文件的i-node编号,此i-node非彼iNode。是Linux/Unix用来识别文件的编号。是的,识别文件用的不是文件名。使用命令’ls –I’可以看到。
  2. 文件最后修改时间
  3. 文件大小
    生成Etag的时候,可以使用其中一种或几种因子,使用抗碰撞散列函数来生成。所以,理论上ETag也是会重复的,只是概率小到可以忽略。
Last-Modified相对与Etag的问题
  1. Last-Modified标注的最后修改只能精确到秒级,如果某些文件在1秒钟以内,被修改多次的话,它将不能准确标注文件的修改时间。

  2. 如果某些文件会被定期生成,当有时内容并没有任何变化,但Last-Modified却改变了,导致文件没法使用缓存。

  3. 有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形。

Etag是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符,能够更加准确的控制缓存。

Last-Modified与ETag是可以一起使用的,服务器会优先验证ETag,一致的情况下,才会继续比对Last-Modified,最后才决定是否返回304。

总结

summery

参考

Powered by Hexo and Hexo-theme-hiker

Copyright © 2019 - 2024 My Wonderland All Rights Reserved.

UV : | PV :