缓存概念

缓存是指代理服务器客户端本地磁盘内保存的资源副本。利用缓存可减少对源服务器的访问,因此也就节省了通信流量和通信时间。
image.png image.png

缓存的优点:

  1. 缓解服务器压力
  2. 加快了加载网页速度
  3. 减少带宽消耗

    缓存的分类

    1. 当ctrl+f5强制刷新网页时,直接从服务器加载,跳过强缓存和协商缓存。
    2. 当f5刷新网页时,跳过强缓存,但是会检查协商缓存。
    3. 浏览器地址栏中写入URL,回车 浏览器发现缓存中有这个文件了,不用继续请求了,直接去缓存拿。(最快)

强缓存

强缓存是当我们访问URL的时候,不会向服务器发送请求,直接从缓存中读取资源,但是会返回200的状态码。

我们第一次进入页面,请求服务器,然后服务器进行应答,浏览器会根据response Header来判断是否对资源进行缓存,如果响应头中expires或者cache-control字段,代表这是强缓存,浏览器就会把资源缓存在memory cache 或 disk cache中。

image.png
第二次请求时,浏览器判断请求参数,如果符合强缓存条件就直接返回状态码200,从本地缓存中拿数据。

否则把响应参数存在request header请求头中,看是否符合协商缓存,符合则返回状态码304,不符合则服务器会返回全新资源。

HTTP缓存 - 图5

协商缓存

协商缓存就是强缓存失效后,浏览器携带缓存标识向服务器发送请求,由服务器根据缓存标识来决定是否使用缓存的过程。

见条件请求

缓存位置

image.png

查找浏览器缓存时会按顺序查找: Service Worker—>Memory Cache—>Disk Cache—>Push Cache。

1. Service Worker

是运行在浏览器背后的独立线程,一般可以用来实现缓存功能。使用 Service Worker的话,传输协议必须为 HTTPS。因为 Service Worker 中涉及到请求拦截,所以必须使用 HTTPS 协议来保障安全。Service Worker 的缓存与浏览器其他内建的缓存机制不同,它可以让我们自由控制缓存哪些文件、如何匹配缓存、如何读取缓存,并且缓存是持续性的。

2. Memory Cache

内存中的缓存,主要包含的是当前中页面中已经抓取到的资源,例如页面上已经下载的样式、脚本、图片等。读取内存中的数据肯定比磁盘快,内存缓存虽然读取高效,可是缓存持续性很短,会随着进程的释放而释放。一旦我们关闭 Tab 页面,内存中的缓存也就被释放了。

3. Disk Cache

存储在硬盘中的缓存,读取速度慢点,但是什么都能存储到磁盘中,比之 Memory Cache 胜在容量和存储时效性上。
在所有浏览器缓存中,Disk Cache 覆盖面基本是最大的。

4. Push Cache

Push Cache(推送缓存)是 HTTP/2 中的内容,当以上三种缓存都没有命中时,它才会被使用。它只在会话(Session)中存在,一旦会话结束就被释放,并且缓存时间也很短暂,在Chrome浏览器中只有5分钟左右,同时它也并非严格执行HTTP头中的缓存指令。

字段解释

两个HTTP/1.0的字段

Pragma

  • Pragma 是HTTP/1.1 之前版本的历史遗留字段,仅作为与HTTP/1.0的向后兼容而定义
  • 规范定义的形式唯一:Pragma: no-cache
  • 该首部字段属于通用首部字段,但只用在客户端发送的请求中。客户端会要求所有的中间服务器不返回缓存的资源
  • 它的行为与Cache-Control: no-cache一致,且它的优先级比 Cache-Control

Expires

  • 响应头
  • Expires 过期时间为绝对时间,指未来某个时间点缓存过期
  • 值为 0 表示资源已过期或非强缓存
  • Cache-Control 为相对时间,相对于当前时间,如 max-age=30表示30s 后缓存过期
  • Expires 的优先级低于 Cache-Control 字段
  • 缺点,就是它判断是否过期是用本地时间来判断的,本地时间是可以自己修改的。

    Cache-Control

    通过指定首部字段 Cache-Control 的指令,就能操作缓存的工作机制。
    指令的参数是可选的,多个指令之间通过“,”分隔。首部字段 Cache-Control 的指令可用于请求响应
    1. Cache-Control: private, max-age=0, no-cache

    当你点“刷新”按钮的时候,浏览器会在请求头里加一个“Cache-Control: max-age=0”。 Ctrl+F5 的“强制刷新”又是什么样的呢?它其实是发了一个“Cache-Control: no-cache” 通常两者的效果是相同的

请求指令

image.png

  • max-stale的意思是如果代理上的缓存过期了也可以接受,但不能过期太多,超过 x 秒也会不要。
  • min-fresh的意思是缓存必须有效,而且必须在 x 秒后依然有效。

响应指令

image.png

  • max-age:时间的计算起点是响应报文的创建时刻
  • no_store:不允许缓存,用于某些变化非常频繁的数据,例如秒杀页面;
  • no_cache:它的字面含义容易与 no_store 搞混,实际的意思并不是不允许缓存,而是可以缓存,但在使用之前必须要去服务器验证是否过期,是否有最新的版本;
  • must-revalidate:又是一个和 no_cache 相似的词,它的意思是如果缓存不过期就可以继续使用,但过期了如果还想用就必须去服务器验证。

image.png

条件请求

形如 If-xxx 这种样式的请求首部字段,都可称为条件请求。服务器接收到附带条件的请求后,只有判断指定条件为真时,才会执行请求。

条件请求一共有 5 个头字段,我们最常用的是“if-Modified-Since”和“If-None-Match”这两个。需要第一次的响应报文预先提供“Last-modified”和“ETag”,然后第二次请求时就可以带上缓存里的原值,验证资源是否是最新的。

如果资源没有变,服务器就回应一个“304 Not Modified”,表示缓存依然有效,浏览器就可以更新一下有效期,然后放心大胆地使用缓存了。
image.png

If-Modified-Since

  • 如果在 If-Modified-Since 字段指定的日期时间后,资源发生了更新,服务器会接受请求
  • 如果请求的资源都没有过更新,则返回状态码 304 Not Modified 的响应
  • If-Modified-Since 用于确认代理或客户端拥有的本地资源的有效性。 获取资源的更新日期时间,可通过确认首部字段 Last-Modified 来确定。 ```javascript 响应:Last-Modified: Wed, 01 Dec 2021 07:08:06 GMT

=>

请求:If-Modified-Since: Wed, 01 Dec 2021 07:08:06 GMT

  1. <a name="pZBYd"></a>
  2. #### If-None-Match
  3. - 只有在 If-None-Match 的字段值与 ETag 值不一致时,可处理该请求。与 If-Match 首部字段的作用相反
  4. - 在 GET 或 HEAD 方法中使用首部字段 If-None-Match 可获取最新的资源。因此,这与使用首部字段 If-Modified-Since 时有些类似。
  5. ```javascript
  6. 响应:etag: W/"f8f5bb334ed87c0dea9e8fe225ad53a7"
  7. =>
  8. 请求:if-none-match: W/"f8f5bb334ed87c0dea9e8fe225ad53a7"


Etag / If-None-Match优先级高于Last-Modified / If-Modified-Since,同时存在则只有Etag / If-None-Match生效。

Last-modified和Etag对比

  • 如果服务端修改了一段代码,然后又改回去了。此时资源文件的修改时间变了,实际上文件没有发生改变。
  • 而 ETag 可以根据内容生成的 hash 来比较的,只要资源文件内容不变,就会应用客户端的缓存,减少不必要的传输。
  • 所以 ETag 比 Last-Modified 缓存更精确、高效和节省带宽

ETag

Etag 是 Entity tag 的缩写,可以理解为“被请求资源的摘要标识”,Etag 是服务端的一个资源的标识,在 HTTP 响应头中将其传送到客户端,类似这样,ETag:W/"50b1c1d4f775c61:df3"

ETag 格式

  • ETag:W/"xxxxxxxx"
  • ETag:"xxxxxxx"

    强类型验证

    比对资源每个字节都要一样。

弱类型验证

W/前缀代表使用
弱 ETag 在值前有个W/标记,只要求资源在语义上没有变化,但内部可能会有部分发生了改变(例如 HTML 里的标签顺序调整,或者多了几个空格)

如果 http 响应头中 ETag 值改变了,是否意味着文件内容一定已经更改?

  • 不一定
  • 文件在一秒内发生了改变而且文件大小不变
  • 这种情况非常极端,概率很低
  • 因此在正常情况下可以容忍一个不太完美但是高效的算法。

彻底理解浏览器缓存机制 https://juejin.cn/post/6947936223126093861