最近一直在面试,也算是查漏补缺吧,好多知识点都学过用过,但是说的不够系统,这个算其中一个,我还是经常总结分享吧。

1.概念

首先要理解这两种缓存都是浏览器的与服务器的协议,都发生在浏览器第一次请求发生后,再次请求时,使用本地缓存的策略。

强缓存:浏览器第一次请求资源时将资源缓存到本地。第二次检查资源是否过期。如果没有过期,则直接使用资源,如果过期,则重新请求请求。
协商缓存:浏览器第一次请求缓存,保存缓存ID和时间。重复请求。浏览器会要求服务器验证资源是否更新。服务器根据缓存ID进行判断。如果没有失效,则使用缓存。在这种情况下,返回 304。通知客户端缓存数据可用。如果失败,则重新发送资源。

一般都是做强缓存的。只有当强缓存失败时,才协商缓存。

缓存状态码请求服务器
强缓存200不,直接从缓存中获取
协商缓存304是的,通过服务器告诉浏览器缓存是否可用

2.强缓存

对于强缓存,响应头中会有两个字段来表示失效规则(Expires/Cache-Control)

1.Expires

Expires 的值是服务器返回的过期时间,即下一次请求时间小于服务器返回的过期时间,直接使用缓存的数据。
Expires 是 HTTP 1.0 的产物,现在默认浏览器都默认使用 HTTP 1.1,所以这里不做赘述。

2.Cache-Control

具体参数定义在rfc2616上可以查到。

值有privatepublicno-cachemax-ageno-store等等

作用
private响应消息的全部或部分是针对单个用户的,不得由共享缓存(例如代理服务器)缓存。
public客户端和代理服务器都可以缓存
max-age=xxx缓存内容将在 xxx 秒后过期
no-cache跳过设置强缓存,但不会阻止设置协商缓存
no-store不缓存,这样会使客户端和服务器都不缓存,所以没有所谓的强缓存,协商缓存
immutable如果请求资源,则直接读取缓存,即使用户进行刷新操作,也不会将请求发送到服务器

3.pragma

Pragma是一个 HTTP/1.0 标头。 Pragma: no-cache就像 Cache-Control: no-cache 它强制缓存在释放缓存副本之前将请求提交给源服务器进行验证。但是,Pragma 没有为 HTTP 响应指定,因此不是通用 HTTP/1.1Cache-Control标头的可靠替代品。

Pragma 应该仅用于与 HTTP/1.0 缓存的向后兼容,其中 Cache-Control HTTP/1.1 的header尚不存在。

3.协商缓存

对于协商缓存,响应头中会有两个字段来表示(Last-Modified / ETag)

1.Last-Modified

Last-Modified 的值表示该响应资源的最后修改时间。响应请求时,Web 服务器告诉浏览器资源的最后修改时间。再次请求资源时,请求头会包含If-Modified-Since域,值在Last-Modified之前返回,如:If-Modified-Since: Mon, 06 Jul 2020 06:27:10 GMT。服务器会比较这个字段的最后修改时间和资源。如果一致,则证明没有被修改,告诉浏览器直接使用缓存,返回304;如果不一致,直接返回修改后的资源,并将Last-Modified修改为新值。

缺点

  • 只要是编辑过的,不管内容是否真的发生了变化,都会以上次修改的时间作为判断依据,作为新的资源返回,造成对请求的不必要的响应,也就是原来缓存的作用是避免不必要的请求。
  • if-Modified-由于时间精度只能达到秒,有些文件修改的非常频繁,比如在不到秒的时间内,(比如1s内修改了N次),这个是无法判断的。

2.ETag

为了解决Last-Modified的上述问题,可以使用用ETag
每个文件都有一个ETag。当您更改文件时,它会更改。它是一个文件哈希,每个文件都是唯一的。就像用webpack打包的时候,每个资源都会有这个东西。比如:app.js 打包后变成了built.85d2fsbf33.js,加上唯一的hash也是为了解决缓存问题。

协商过程

  • 发送请求->查看资源是否过期->过期->请求服务器->服务器比较资源是否真的过期->未过期->返回304状态码->客户端缓存使用的旧资源。
  • 发送请求 -> 查看资源是否过期 -> 过期 -> 请求服务器 -> 服务器比较资源是否真的过期 -> 过期 -> 返回 200 状态码 -> 客户端就像第一次收到资源,在缓存控制中记下它的 Max-age、etag、last-modified 等。

请求资源时,同时将用户本地的资源etag带到服务器,服务器与最新的资源进行比较。
如果资源没有变化,返回304,浏览器读取本地缓存。
如果资源发生了变化,则返回200,并返回最新的资源。

3.访问刷新分析

访问和刷新分为以下三种情况:

  • 输入URL
  • 按刷新键,F5刷新,在网页上右键重新加载
  • ctrl + F5 强制刷新

1.输入URL

在这种情况下,将使用缓存策略的实际设计来判断。

  • 如果你先走强缓存路线。根据cache-control(expires的优先级低)判断缓存是否已经过期。如果它没有过期,则返回 200(从缓存中)。
  • 如果本地缓存已经过期再去协商缓存路由,根据之前的last-modified值与服务器比较

    • 如果此时间后没有变化,则读取本地缓存并返回304。
    • 否则,返回新资源,状态码 200,并更新返回响应的最后修改值。

2.按刷新键,F5刷新,在网页上右键“重新加载

在这种情况下,浏览器实际上会将cache-controlmax-age直接设置为0,让缓存立即过期,直接去协商缓存路由。

3.CTRL+ F5 强制刷新

在强制刷新的情况下,浏览器会强制设置no-cache为强制访问最新资源,甚至直接去掉了If-Modified-Since/If-None-Match等请求头。

4.请求头

在上文中提及到了If-Modified-Since/If-None-Match等请求头,该请求头的值是浏览器在发送第一次请求后从响应头中获取的。

1.If-Modified-Since

该域对应第一次请求时浏览器返回的Last-Modified的值,浏览器将获取到的该值返回给服务器,如果该URI没有更新的话会返回304让浏览器取本地缓存,反之如果有更新的话会返回200并且会更新If-Modified-Since的值。

2.If-None-Match

同样的,这里对应第一次从服务器获取的ETag的值,在后面的请求中发送给服务器并且由服务器进行比较,如果不相同的话会返回200并且会返回新的ETag,如果没有变化则返回304。

文章目录
3人点赞