http缓存控制你了解嘛

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第10天,点击查看活动详情

基本认知

Web 服务缓存 大致可以分为:数据库缓存、服务器端缓存(代理服务器缓存、CDN 服务器缓存)、浏览器缓存。

浏览器缓存 也包含很多内容: HTTP 缓存、indexDB、cookie、localstorage 等等。这里我们只讨论 HTTP 缓存相关内容

HTTP缓存: (优化页面加载的效率, 如果没有缓存策略, 每次重新加载页面, 会非常慢!)

  • 强缓存
  • 协商缓存

在具体了解 HTTP 缓存之前先来明确几个术语:

  • 缓存命中率:从缓存中得到数据的请求数 与 所有请求数的比率。理想状态是越高越好。

    (看所有的请求中, 多少从缓存中读的)

  • 过期内容:超过设置的有效时间,被标记为“陈旧”的内容。

  • 验证:验证缓存中的过期内容是否仍然有效,验证通过的话刷新过期时间。

  • 失效:失效就是把内容从缓存中移除。

浏览器缓存主要是 HTTP 协议定义的缓存机制。

浏览器缓存, HTTP缓存分类

浏览器缓存分为强缓存协商缓存,浏览器加载一个页面的简单流程如下:

  1. 浏览器先根据这个资源的 http头信息判断是否命中强缓存

    如果命中则直接加载在缓存中的资源,并不会将请求发送到服务器。(强缓存)

  2. 如果未命中强缓存,则浏览器会将资源加载请求发送到服务器。

    服务器来判断浏览器本地缓存是否失效。

    若可以使用,则服务器并不会返回资源信息,浏览器继续从缓存加载资源。(协商缓存)

  3. 如果未命中协商缓存,则服务器会将完整的资源返回给浏览器,浏览器加载新资源,并更新缓存。(新的请求)

强缓存 (验证缓存是否过期)

(进行判断缓存是否有效, 就是判断资源是否过期, 如果未过期, 直接用缓存)

强缓存

命中强缓存时,浏览器并不会将请求发送给服务器。

在Chrome的开发者工具中看到http的返回码是200,但是在Size列会显示为(from cache)。

940884-20180423141536107-329179455.png

强缓存是利用http的返回的响应头中的Expires或者Cache-Control (优先级更高) 两个字段来控制的,用来表示资源的缓存时间。

Expires: 指定一个具体时间(2020年12月12日 17:00), 到了这个时间了, 缓存过期了, 在时间内, 都是有效的, 可以直接读

Cache-Control : 指定一个过期时间 (3600s), 这个资源你加载到后, 可以用 3600s

Expires

缓存过期时间,用来指定资源到期的时间,是服务器端的具体的时间点。也就是说,Expires=max-age + 请求时间,需要和Last-modified结合使用。但在上面我们提到过,cache-control的优先级更高。

Expires是Web服务器响应消息头字段,在响应http请求时告诉浏览器在过期时间前浏览器可以直接从浏览器缓存取数据,而无需再次请求。

image-20210308182724715.png

该字段会返回一个时间,比如Expires: Wed, 23 Nov 2050 16:00:01 GMT 。这个时间代表着这个资源的失效时间,也就是说在xx年xx月xx日时间之前都是有效的,即命中缓存。

这种方式有一个明显的缺点,由于失效时间是一个绝对时间,所以当 服务器与客户端 时间偏差很大 以后,就会导致缓存混乱。于是发展出了Cache-Control。

Cache-Control

Cache-Control是一个相对时间,例如Cache-Control:max-age 3600,代表着资源的有效期是3600秒。

由于是相对时间,并且都是与客户端时间比较,所以服务器与客户端时间偏差也不会导致问题。

Cache-Control与Expires可以在服务端配置同时启用或者启用任意一个,同时启用的时候Cache-Control优先级高。

Cache-Control 可以由多个字段组合而成,主要有以下几个取值:

  1. max-age 指定一个时间长度,在这个时间段内缓存是有效的,单位是s。

    例如设置 Cache-Control:max-age=31536000,也就是说缓存有效期为(31536000 / 24 / 60 / 60)天,

    第一次访问这个资源的时候,服务器端也返回了 Expires 字段,并且过期时间是一年后。

image-20210308182737673.png

在没有禁用缓存并且没有超过有效时间的情况下,再次访问这个资源就命中了缓存,不会向服务器请求资源而是直接从浏览器缓存中取。

  1. no-cache 强制所有缓存了该响应的用户,在使用已缓存的数据前,发送带验证的请求到服务器, 问服务器是否可以读缓存。

    不是字面意思上的不缓存。

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

注意: 如果命中强缓存, 在有效期内, 使用了本地浏览器的缓存, 请求该资源是不会向服务器发送请求的! (大大减轻了服务器压力)

协商缓存 (强缓存未命中-发送请求进行协商)

看看过期时间, 食品没过期, 直接吃 (直接读缓存, 不发请求) 命中强缓存!

食品过期时间过了, 能不能吃呢? 问问专家(服务器), 专家瞅了一眼, 还能吃, 不会死人, 重新标了个过期时间(有科学依据)

(响应304, 不返回内容) , 可以用 (协商缓存)

如果问过专家(服务器), 专家瞅了一眼, 呀真不能用了, 原来的不要了, 我重新给你发一个 (响应200, 并返回内容)

协商缓存

若未命中强缓存(强缓存过期了),则浏览器会将请求发送至服务器。

服务器根据http头信息中的Last-Modify/If-Modify-SinceEtag/If-None-Match来判断是否命中协商缓存。

如果命中,则http返回码为304 (你本地之前加载的资源是有效的),浏览器从缓存中加载资源。

Last-Modify/If-Modify-Since

浏览器第一次请求一个资源的时候, 服务器返回的header中会加上Last-Modify,

Last-modify是一个时间标识该资源的最后修改时间,例如Last-Modify: Thu,31 Dec 2037 23:59:59 GMT

image-20210308182821236.png

当浏览器再次请求该资源时(进行协商请求时),发送的请求头中会包含If-Modify-Since,该值为缓存之前返回的Last-Modify

服务器收到If-Modify-Since后,根据实际服务器的资源的最后修改时间, 进行判断是否命中缓存。

940884-20180423141732879-1484228353.png

如果命中缓存,则返回 http304,并且不会返回资源内容,并且不会返回Last-Modify。

image-20210308123308326.png

由于对比的是服务端的修改时间,所以就算客户端与服务端时间差距, 也不会有问题。

但是有时候通过最后修改时间来判断资源是否修改还是不太准确(资源变化了最后修改时间也可以一致)。

比如: 最后修改只能精确到秒级, 一秒进行了多次修改, 就不行了, 于是出现了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值来判断是否命中缓存。

image-20210308182858733.png

ETag生成靠以下几种因子

  1. 文件的i-node编号,是Linux/Unix用来识别文件的编号。

  2. 文件最后修改时间

  3. 文件大小

    ...

生成Etag的时候,可以使用其中一种或几种因子,使用抗碰撞散列函数来生成。生成一个标记文件的唯一值

既生 Last-Modified 何生 Etag ?

你可能会觉得使用Last-Modified已经足以让浏览器知道本地的缓存副本是否足够新,为什么还需要Etag(实体标识)呢?

Etag的出现主要是为了解决几个Last-Modified比较难解决的问题:

  1. Last-Modified标注的最后修改只能精确到秒级

    如果某些文件在1秒钟以内,被修改多次的话,它将不能准确标注文件的修改时间

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

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

不会仅仅只根据最后的修改时间判断是否进行使用缓存

Last-Modified与ETag是可以一起使用的,服务器会优先验证ETag,一致的情况下,才会继续比对Last-Modified,

最后才决定是否返回304。

小结:

  • 强缓存: 检查过期时间, 判断缓存是否失效, 如果不失效, 直接用, 不发请求

    大大的减少了 服务器的请求次数, 在过期时间内, 直接从客户端内存中读

  • 协商缓存: 强缓存命中失效了, 超过过期时间了, 拿着标识(最后的修改时间, 唯一标识etag), 去问服务器, 是否真的过期了

    如果验证通过, 服务器会直接响应 304, 且不会返回资源

不太会变的资源 => 图片, 非常的适合应用强缓存 (过期时间也可以设置的很长)

如果是一些很可能会变的资源, 也希望能缓存 => 过期时间设置短一些, 一旦过期, 协商缓存

实际工作两者相互配合

整体请求缓存流程

浏览器第一次请求

image-20210308182913833.png

浏览器第二次请求

image-20210308182925144.png

猜你喜欢

转载自juejin.im/post/7084998510998716424
今日推荐