HTTP 缓存了解一下

349 阅读6分钟

Web 文章首发于 两个程序猿 微信公众号,希望能和大家多多交流,共同进步~

目录
  1. 简介
  2. 缓存处理过程
  3. 缓存控制首部
  4. 强缓存、协商缓存

缓存简介

Web 缓存是可以自动保存在代理服务器或者客户端本地磁盘内常见文档副本的http设备。当 web 请求抵达缓存时,如果本地有 “已缓存的” 副本,就可以从本地存储设备提取这个文档。

使用缓存的优点

  • 减少冗余数据的传输,节省通信流量和通信时间
  • 缓解网络瓶颈的问题,更快加载页面
  • 降低对原始服务器的要求,避免过载出现
  • 降低距离时延

缓存处理过程

  1. 接收 --- 从网络中读取抵达的请求报文
  2. 解析 --- 解析报文,提取出 URL 和首部
  3. 查询 --- 查询本地是否有副本可以用,如果没有就获取一份副本并保存
  4. 新鲜度检测 --- 检测已缓存的副本是否新鲜,若不新鲜,询问服务器是否有改动
  5. 创建响应 --- 用新的首部和已缓存的主体构建响应报文
  6. 发送 --- 返回给客户端
  7. 日志 --- 创建日志描述这个事件(可选)

缓存控制首部

服务器可以通过这几种方式,来控制缓存

  • 附加 cache-control: no-store、no-cache、must-revalidate、max-age 到响应中
  • 附加 expires 到响应中(不推荐使用)
  • 不附加过期信息,让缓存确定自己的过期日期

must-revalidate:原始服务器希望缓存严格遵守过期信息。告诉缓存,在事先没有跟原始服务器进行在验证的情况下,不能提供这个对象的陈旧副本。缓存仍然可以提供新鲜的副本。如果缓存进行新鲜度检查时,原始服务器不可用,缓存必须返回 504 错误。

如果响应中没有cache-control:max-age, 也没有expires首部,缓存可以计算出一个试探性最大使用期。

 no-store: 禁止缓存对响应进行复制
 no-cache:可以把响应存在本地的缓存区中,只是在新鲜度验证之前,不可提供给客户端。

HTTP1.1 提供 Pragma: no-cache 是为了兼容 HTTP1.0+。

为了更好的理解这几个字段,可以看一下chrome官方给出的流程图

1.Cache-Control 设置 no-store,拒绝一切形式的缓存。

2.考虑是否每次都需要向服务器进行缓存有效确认,如果需要,那么设 Cache-Control 的值为 no-cache。

3.考虑该资源是否可以被代理服务器缓存,根据其结果决定是设置为 private 还是 public

4.然后考虑该资源的过期时间,设置对应的 max-age 和 s-maxage 值

5.配置协商缓存需要用到的 Etag、Last-Modified 等参数。

强缓存和协商缓存

强缓存

强缓存:服务器返回响应时,在 Response Headers 中返回 Expires 或 Cache-Control 这两个字段表示强缓存。若命中强缓存,直接从缓存中获取资源,不在向服务器发起请求。强缓存的优先级高于协商缓存。

expires 和 cache-control

expires cache-control
是一个时间戳 时间长度(max-age)
优先级低 优先级高
expires:

在过去,使用 expires 来实现强缓存,但是 expires 有一些问题,它是用时间戳来表示的,当再次请求资源时,浏览器会把本地时间和 expires 时间戳进行对比,而当客户端时间改变时,expires将无法达到预期。

cache-control:

因为 expires 的局限性,HTTP1.1 新增了 cache-control 字段来完美的替代 expires。

cache-control: max-age=3600, s-maxage=31536000

在 cache-control 中,我们用 max-age、s-maxage 来实现强缓存,控制资源有效期。max-age 是一个以秒为单位的时间长度,表示该资源在 xxxx 秒内都是有效的。当值为0时,表示不缓存。

比 expires 更加精准,优先级也更加高,当 expires 和 cache-control 同时出现时,以 cache-control 为准。

s-maxage 表示代理服务器上缓存的有效时间,只在代理服务器上生效,只对共享(共有)缓存有效。

如果缓存文档仅仅是过期了,但是它和原始服务器上的文件是没有区别的。这时候缓存要询问原始服务器文档是否存在变化。

  • 如果缓存向原始服务器再验证时,显示文件内容 发生 变化,缓存会获取一份新的文档的副本。
  • 如果缓存向原始服务器再验证时,显示文件内容 未发生 变化,缓存只需要获取新的首部并更新,包括新的过期时间(cache-control)。

协商缓存

在协商缓存机制下,浏览器需要向服务器去询问缓存的相关信息,进而判断是重新发起请求、下载完整的响应,还是从本地获取缓存的资源。

Last-Modified 和 Etag

Last-Modified Etag
时间格式:Wed, 22 Jul 2009 07:08:07 GMT 是以内容计算出的一个标识
与请求头中的 If-Modified-Since 对应 与请求头中的 If-None-Match 对应
Last-Modified:

在首次请求的时候,响应头会返回 last-modified,在之后的请求头中会带有一个 if-modified-since 的字段,值是上次响应头中返回的 last-modified 的值。服务器接收到这个值,会和本地的 last-modified 值相比,判断资源是否发生变化。

  • 发生 变化,返回完整的带有新主体的 200 响应,并更新响应头的 last-modified。
  • 未发生 变化,返回一个 304 Not Modify 响应报文,不会返回文档主体, 不会更新响应头中的 last-modified

缺点:

  1. 若文档的最后修改时间改变,但是内容并没有变化或者修改并不重要(拼写或者注释的修改),这时会被认为文档资源发生了变化。
  2. 若修改文档动作发生很快,在几百毫秒之间,由于 If-Modified-Since 没有检查到这次改动(If-Modified-Since只能检查到秒单位时间差内的改动),误判为文档资源未发生变化。
Etag:

由于使用 last-modified 字段,服务器不能正确的感知到文档内容的变化,为了解决这些问题,所以Etag出现了, 它可能是文档序列号,版本名,或文档内容的校验或其他指纹信息。当文档修改时,Etag就会改变。

和 last-modified 类似,首次请求时,在响应头中获取到 ETag, 下次请求时,会在请求头中带有 If-None-Match 和服务端进行对比。

  • 若 ETag 发生 改变,服务器会返回带有新主体的 200 的响应以及新的ETag
  • 若 ETag 未发生 改变,服务器返回 304 Not Modify 的响应。
公有缓存和私有缓存

1.公有缓存是特殊的共享代理服务器,称为 缓存代理服务器 或 代理缓存。代理缓存接受来自多个用户的访问,可以很好的减少冗余流量。
2.私有缓存是个人缓存,不需要很大的存储空间。

HTTP 缓存的知识到这里就结束了,有不正确的地方,希望大家指正,我们共同学习。