2. 缓存策略模式详解:CacheStrategy决策树,CacheControl指令解析,强制缓存与协商缓存

2.1 核心概念:强制缓存与协商缓存

HTTP 缓存机制是 OkHttp 离线缓存策略的根基,它分为两种核心模式:强制缓存(强缓存)与 协商缓存(弱缓存)。理解这两者的区别,是掌握 CacheStrategy 决策树的前提。

  • 强制缓存:客户端直接从本地缓存中读取数据,不与服务器发生任何网络交互。状态码表现为 200 (from cache)。只要缓存未过期(由 max-age 控制),OkHttp 将直接返回缓存对象。
  • 协商缓存:当强制缓存失效或显式要求验证时,客户端会向服务器发送验证请求(携带 If-None-Match 或 If-Modified-Since)。若资源未变更,服务器返回 304 Not Modified,客户端继续使用缓存;若已变更,服务器返回完整的 200 OK 响应。
特征 强制缓存 协商缓存
触发条件 缓存未过期,max-age > 0 缓存过期,no-cache,验证头存在
HTTP 状态码 200 (from cache) 304 Not Modified 或 200 OK
优势 零网络开销,毫秒级响应 保证数据新鲜,304 响应不含 body 节省带宽
劣势 服务器更新后客户端可能暂存过期数据 至少有一次网络往返延迟
OkHttp 实现 CacheControl.Builder().maxAge(10, MINUTES) CacheControl.Builder().noCache() / 自动条件请求

2.2 CacheControl 指令深度解析

OkHttp 提供了 CacheControl 类,用于在请求和响应中精确控制缓存行为。以下是核心指令及其在 OkHttp API 中的映射关系:

  • max-age(seconds, unit):缓存的最大存活时间。响应经过此时间后即视为过期。
  • noCache():禁止强制缓存,要求每次使用缓存前都必须向服务器验证其新鲜度(协商缓存)。
  • noStore():完全禁止缓存,请求和响应不得存储在缓存目录中。
  • onlyIfCached():仅从本地缓存获取数据。若缓存不存在或已过期,直接返回 504 Unsatisfiable Request。
  • minFresh(seconds, unit):指定缓存至少还要保持新鲜的秒数,如果预期即将过期则不使用。
  • maxStale(seconds, unit):允许返回已经过期的缓存,只要过期时间不超过指定的秒数。
// 请求级覆盖:强制使用网络
Request networkRequest = new Request.Builder()
        .url("https://api.example.com/data")
        .cacheControl(CacheControl.FORCE_NETWORK)
        .build();

// 请求级覆盖:强制使用缓存(如果没有缓存则返回504)
Request cacheOnlyRequest = new Request.Builder()
        .url("https://api.example.com/data")
        .cacheControl(CacheControl.FORCE_CACHE)
        .build();

// 自定义:允许接受最多1分钟过期的缓存
Request staleRequest = new Request.Builder()
        .url("https://api.example.com/data")
        .cacheControl(new CacheControl.Builder()
                .maxStale(1, TimeUnit.MINUTES)
                .build())
        .build();
优先级规则:服务器返回的 Cache-Control 指令优先级高于客户端请求指令。例如服务器指定 no-store 时,客户端的 max-age 请求指令将无效。

2.3 CacheStrategy 决策树内部机制

CacheStrategy 是 OkHttp 缓存策略的核心协调器。它根据当前请求的 CacheControl 指令、缓存响应的 CacheControl 指令以及缓存的年龄,对三个结果进行决策:返回缓存、发起网络请求、返回 504 错误。下方流程图描绘了这一决策树逻辑的完整路径。

源码核心逻辑解读: OkHttp 的 CacheStrategy 工厂通过判断 strategy.networkRequest 和 strategy.cacheResponse 是否为 null 来路由决策。若 networkRequest 为 null 则强制缓存;若 cacheResponse 为 null 则返回 504;两者均不为 null 则进入协商缓存流程。
流程图:CacheStrategy 决策树 发起网络请求 本地是否有缓存? 返回 504 错误 缓存是否新鲜? 返回缓存数据 (200) 发起协商请求 服务器返回 304? 返回缓存 (304) 返回新数据 (200) 新鲜度计算 max-age vs age CacheControl 指令 否 是 是 否 是 ← 上一章 📖 返回目录 下一章 →