当前位置:网站首页>HTTP的缓存控制

HTTP的缓存控制

2022-06-24 19:35:00 Nice2cu_Code

HTTP的缓存控制

由于网络时延不可控,浏览器使用 HTTP 从服务器获取资源的成本较高。所以,非常有必要把“来之不易”的数据缓存起来,下次再请求的时候尽可能地复用而不必去服务器中查找。这样,就可以避免多次请求 - 应答的通信成本,节约网络带宽,也可以加快响应速度。

1. 服务器的缓存控制

缓存使用的流程如下:

  1. 浏览器发现缓存无数据,于是发送请求,向服务器获取资源
  2. 服务器响应请求,返回资源,同时标记资源的有效期
  3. 浏览器缓存资源,等待下次重用

服务器标记资源有效期使用的头字段是 “Cache-Control”,里面的值 “max-age=30” 就是资源的有效时间,相当于告诉浏览器,“这个页面只能缓存 30 秒,之后就算是过期,不能用,如果要访问必须重新从服务器获取。在没有禁用缓存并且没有超过有效时间的情况下,再次访问这个资源就命中了缓存,不会向服务器请求资源而是直接从浏览器缓存中取。

注意:有效时间的计算起点是服务器端的响应报文创建时刻,而不是客户端收到报文的时刻,也就是说包含了在链路传输过程中所花费的时间。比如,服务器设定“max-age=5”,但因为网络质量很糟糕,等浏览器收到响应报文已经过去了 4 秒,那么这个资源在客户端就最多能够再存 1 秒钟,之后就会失效。

其余常用缓存属性:

  • no_store:不允许缓存,用于某些变化非常频繁的数据,例如秒杀页面
  • no_cache:它的字面含义容易与 no_store 搞混,实际的意思并不是不允许缓存,而是可以缓存,但在使用之前必须要去服务器验证是否过期,是否有最新的版本,如果有就使用服务器最新的版本
  • must-revalidate:它的意思是如果缓存不过期就可以继续使用,但过期了如果还想用就必须去服务器验证是否可用

补充:

与头字段 “Cache-Control” 类似,Expires 响应头表示缓存过期的时间点,超过了这个时间点就代表资源过期,但由于时区不同的问题这种方式已经几乎不再使用,两个同时存在时也是 Cache-Control 的优先级更高。

2. 客户端的缓存控制

不止服务器可以发 “Cache-Control” 头,浏览器也可以发 “Cache-Control”,也就是说请求 - 应答的双方都可以用这个字段进行缓存控制,互相协商缓存的使用策略。

当点击 “刷新” 按钮的时候,浏览器会在请求头里加一个 “Cache-Control: max-age=0”。表示需要一个最新的内容,而本地缓存里的数据至少已经存在了几秒钟,不是最新的,所以浏览器就不会使用缓存,而是向服务器发请求。服务器看到 max-age=0,也就会用一个最新生成的报文回应浏览器。

当点击 Ctrl+F5 “强制刷新” 时,浏览器会发送一个 “Cache-Control: no-cache”,含义和 “max-age=0” 基本一样,通常两者的效果是相同的,也就是不使用缓存。

当使用 “前进”、“后退”、”重定向跳转“ 时,浏览器使用了缓存,在进行这些操作时,只用最基本的请求头,没有 “Cache-Control”,所以就会检查缓存,直接利用之前的资源,不再进行网络通信。

3. 条件请求

缓存的资源到期了,并不意味着资源内容发生了改变,如果和服务器上的资源没有差异,实际上没有必要再次请求服务器。客户端使用条件请求验证当前资源是否被修改过,条件请求有两对机制:Last-Modified / If-Modified-Since 和 Etag / If-None-Match。

3.1 Last-Modified / If-Modified-Since

  1. 服务器在首次响应请求时,告诉浏览器资源的最后修改时间 Last-Modified

    image-20210811212432712
  2. 浏览器再次请求资源时,如果没有过期直接从缓存中读取,如果过期了,就要向服务器发起请求,通过 If-Modified-Since 字段通知服务器上次请求时,服务器返回的资源的最后修改时间

    image-20210811212657237
  3. 服务器收到请求后发现有头 If-Modified-Since,则与被请求资源的最后修改时间进行比对

  4. 如果比对成功,则说明资源无新修改,响应 304 NOT Modified,告知浏览器继续使用所保存的cache,304只返回header部分,通过状态码通知客户端使用缓存,不需要将报文主体部分返回给客户端

  5. 如果比对失败,则说明资源被改动过,响应整片资源内容,返回状态码200,响应体中就是该资源当前最新的内容

3.2 Etag / If-None-Match

HTTP1.1用ETag来判断请求的文件是否被修改过,主要为了解决Last-Modified无法解决的一些问题:

  • 一些文件也许会周期性的更改,但是他的内容并不改变(仅仅改变的修改时间),这个时候并不希望客户端认为这个文件被修改了重新GET;

  • 某些文件修改非常频繁,1秒内修改了N次,If-Modified-Since 能检查到的粒度是秒级的,这种修改无法判断

  • 某些服务器不能精确的得到文件的最后修改时间

Etag / If-None-Match工作流程:

  1. 服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识 Etag

    image-20210811213419804
  2. 浏览器再次请求服务器时,通过 If-None-Match 字段通知服务器客户端收到的上次服务器通知的缓存数据的唯一标识

    image-20210811213545267
  3. 服务器收到请求后发现有头 If-None-Match,则与被请求资源的唯一标识进行比对,不同,说明资源被改动过,则响应整片资源内容,返回状态码200。相同,说明资源无新修改,则响应HTTP 304,告知浏览器继续使用所保存的cache

注意:

  1. 如果一些资源的最后修改时间改变了,但是内容没改变,使用 Last-modified 看不出内容没有改变,但是 Etag 可以判断是否发生改变,所以 Etag 的精度比 Last-modified 高。同时使用两对条件请求时,Etag / If-None-Match 优先级更高。

  2. ETag 还有“强”、“弱”之分

    强 ETag 要求资源在字节级别必须完全相符,弱 ETag 在值前有个 “W/” 标记,只要求资源在语义上没有变化,但内部可能会有部分发生了改变(例如 HTML 里的标签顺序调整,或者多了几个空格)。

原网站

版权声明
本文为[Nice2cu_Code]所创,转载请带上原文链接,感谢
https://gaoqize.blog.csdn.net/article/details/119635557