OkHttp 知识梳理(3) - OkHttp 之缓存基础

OkHttp 知识梳理系列文章

OkHttp 知识梳理(1) - OkHttp 源码解析之入门
OkHttp 知识梳理(2) - OkHttp 源码解析之异步请求 & 线程调度
OkHttp 知识梳理(3) - OkHttp 之缓存基础


一、缓存基础

在了解OkHttp的缓存实现之前,我们先来复习一下HTTP协议当中,与缓存有关的一些基础知识,这里,我们会介绍HTTP中与缓存相关的首部字段,根据首部字段的作用,可以将其分为以下四类:

通用首部字段

  • 请求报文和响应报文都会使用的首部。
  • Cache-Control

请求首部字段

  • 从客户端向服务器发送请求报文时使用的首部,补充了请求的附加内容、客户端信息、响应内容相关优先级等信息。
  • If-MatchIf-Modified-SinceIf-None-MatchIf-RangeIf-Unmodified-Since

响应首部字段

  • 从服务器向客户端返回响应报文时使用的首部,补充了响应的附加内容,也会要求客户端附加额外的内容信息。
  • ETag

实体首部字段

  • 针对请求报文和响应报文的实体部分使用的首部,补充了资源内容更新时间等与实体有关的信息。
  • Last-Modified

二、通用首部字段

2.1 简介

在通用首部字段中,与缓存有关的字段为Cache-ControlCache-ControlHTTP/1.1的通用首部字段,通过指定它的值,就能够操作缓存的工作机制。指令的参数是可选的,多个指令之间通过","分隔,首部字段Cache-Control的指令可用于 请求及响应 时。

Cache-Control : private, max-age=0, no-cache 

缓存请求指令

指令 说明
no-cache 强制向源服务器再次验证
no-store 不缓存请求或响应的任何内容
max-age=[s] 响应的最大age
max-stale=[s] 接收已过期的响应
min-fresh=[s] 期望在指定时间内的响应仍然有效
no-transform 代理不可更改媒体类型
only-if-cached 从缓存获取资源
cache-extension 新指令标记

缓存响应指令

指令 说明
public 可向任意方提供响应的缓存
private 仅向特定用户返回响应
no-cache 缓存前必须先确认其有效性
no-store 不缓存请求或响应的任何内容
no-transform 代理不可更改媒体类型
must-revalidate 可缓存但必须再向源服务器确认
proxy-revalidate 要求中间缓存服务器对缓存的响应有效性再进行确认
max-age=[s] 响应的最大age
s-maxage=[s] 公共缓存服务器响应的最大age
cache-extension 新指令标记

2.2 具体含义

2.2.1 public

Cache-Control : public

当指定使用public指令时,则明确表示其它用户也可以利用缓存。

2.2.2 private

private
Cache-Control : private

当指定private指令时,响应只以特定的用户作为对象,这与public指令的行为相反,缓存服务器会对该特定的用户提供资源缓存的服务,对于其他用户发送过来的请求,代理服务器则不会返回缓存。

2.2.3 no-cache

no-cache
Cache-Control : no-cache

使用no-cache的指令的目的是为了 防止从缓存中返回过期的资源

客户端发送的请求 中如果包含no-cache指令,则表示客户端将不会接收缓存过的指令。于是,“中间”缓存服务器必须把客户端请求转发给源服务器。

服务器返回的响应 中包含no-cache指令,那么缓存服务器不能对资源进行缓存,源服务器以后也将不再对缓存服务器请求中提出的资源有效性进行确认,且禁止缓存服务器对响应资源进行缓存操作。

Cache-Control : no-cache=Location

由服务器返回的响应中,若报文首部字段Cache-Control中对no-cache字段名具体制定参数值,那么客户端在接收到这个被指定参数值的首部字段对应的响应报文后,就不能使用缓存,换言之,无参数值的首部字段可以使用缓存,只能在响应指令中指定该参数。

2.2.4 no-store

Cache-Control : no-store

当使用no-store指令时,暗示请求(和对应的响应)或响应中包含机密信息,因此,该指令规定缓存不能在本地存储请求或响应的任一部分。

它和no-cache的区别在于,no-cache代表 不缓存过期的资源,而no-store真正的不缓存

2.2.5 s-maxage

Cache-Control : s-maxage=604800 (秒)

s-maxagemax-age指令的功能相同,它们的不同点是s-maxage指令只适用于供多位用户使用的公共缓存服务器,也就是说,对于向同一用户重复返回响应的服务器来说,这个指令没有任何作用。

另外,当使用s-maxage指令后,则直接忽略对Expires首部字段及max-age指令的处理。

2.2.6 max-age

max-age
Cache-Control : max-age=604800 (秒)

客户端发送的请求 中包含max-age指令时,如果判定缓存资源的缓存时间数值比指定时间的数值更小,那么客户端就接收缓存的资源。另外,当指定max-age值为0时,那么缓存服务器通常需要将请求转发给源服务器。

服务器返回的响应 中包含max-age指令时,缓存服务器将不对资源的有效性再做确认,而max-age数值代表资源保存为缓存的最长时间。

HTTP/1.1版本中,会优先处理max-age指令,而忽略Expires首部字段。

2.2.7 min-refresh

min-refresh
Cache-Control : min-refresh=60 (秒)

min-refresh指令要求缓存服务器返回 至少还未过指定时间的缓存资源。比如,当指定min-refresh60s后,在这60s以内如果有超过有效期限的资源都无法作为响应返回了。

2.2.8 max-stale

Cache-Control : max-stale=3600 (秒)

使用max-stale可指示缓存资源,即使过期也照常接收。如果指令未指定参数,那么无论多久,客户端都会接收响应;如果指令中指定了具体数值,那么即使过期,只要仍处于max-stale指定的时间内,仍旧会被客户端接收。

2.2.9 only-if-cached

Cache-Control : only-if-cached

使用only-if-cached指令表示客户端 仅在缓存服务器本地缓存目标资源的情况下才会要求其返回。换言之,该指令要求缓存服务器不重新加载响应,也不会再次确认资源有效性。若发生请求缓存服务器的本地缓存无响应,则返回504

2.2.10 must-revalidate

Cache-Control : must-revalidate

使用must-revalidate指令,代理会 向源服务器再次验证即将返回的响应缓存目前是否仍然有效

若代理无法连通源服务器再次获取有效资源的话,缓存必须给客户一条504状态码。

另外,使用must-revalidate指令会忽略请求的max-stale指令。

2.2.11 proxy-revalidate

Cache-Control : proxy-revalidate

proxy-revalidate指令要求所有的缓存服务器在接收到客户端带有该指令的请求返回响应之前,必须再次验证缓存的有效性。

2.2.12 no-transform

Cache-Control : no-transform

使用no-transform指令规定无论是在请求还是响应中,缓存都不能改变主体的媒体类型。这样做可防止缓存或代理压缩图片等类似操作。

三、请求首部字段

在请求首部字段中,与缓存相关的字段为If-XXX,像这种样式的请求首部字段,也称为条件请求,服务器接收到附带条件的请求后,只有判断指定条件为真时,才会执行请求。

3.1 If-Match

If-Match

首部字段If-Match会告诉服务器匹配资源所用的实体标记ETag。服务器会比对ETag的字段值与资源的ETag值,仅当两者一致时,才会执行请求,反之则返回状态码412

还可以使用*指定If-Match的字段值,针对这种情况,服务器将会忽略ETag的值,只要资源存在就处理请求。

3.2 If-Modified-Since

If-Modified-Since

首部字段If-Modified-Since会告知服务器若字段值早于资源的更新时间,则希望处理该请求,反之,则返回状态码304

If-Modified-Since用于确认代理或客户端拥有的本地资源的有效性,获取资源的更新日期时间,可通过确认首部字段Last-Modified

3.3 If-None-Match

If-None-Match

If-Match作用相反。

3.4 If-Unmodified-Since

If-Modified-Since作用相反。

四、响应首部字段

首部字段ETag能告知客户端实体标识。它是一种可将资源以字符串形式做唯一性标识的方式。服务器会为每份资源分配对应的ETag值。

另外,当资源更新时,ETag值也需要更新。生成ETag值时,并没有统一的算法规则,而仅仅是由服务器来分配。

强 ETag 值和弱 ETag 值

  • ETag值,无论实体发生多么细微的变化都会改变其值。
  • ETag值,只用于提示资源是否相同。只有资源发生了根本改变,产生差异时才会改变ETag的值。

五、实体首部字段

首部字段Last-Modified指明资源最终修改的时间。一般来说,这个值就是Request-URI指定资源被修改的时间。但类似使用CGI脚本进行动态数据处理时,该值有可能会变成数据最终最终修改时的时间。