第1章 离线缓存核心概念

离线缓存是REST API客户端在失去网络连接后,仍能从本地存储中读取先前的响应,并在恢复网络时与服务器同步的技术。理解缓存命中、失效、离线模式、一致性(Coherence)以及HTTP Cache-Control指令,是构建可靠离线缓存方案的基石。本章逐一剖析这些概念,并给出可操作的影响与配置示例。

1.1 缓存命中与失效

概念定义客户端表现代价
缓存命中请求的资源在本地缓存中存在且未过期立即返回本地数据,无网络延迟占用本地存储空间
缓存失效缓存数据因过期、被主动清除或服务器声明不可用需要发起网络请求刷新资源网络延迟、流量损耗
实践建议:合理设置资源优先级——频繁变动的API使用较短的过期时间(如5分钟),静态资源(图标、版本号)使用较长过期时间(如1天),以减少不必要的缓存失效请求。

1.2 离线模式与一致性(Coherence)

离线模式指客户端完全脱离网络后,仅依靠缓存中的数据提供服务。此时,若缓存中的数据在服务器端已更新,则会出现数据不一致问题。一致性(Coherence)即保证离线期间本地缓存与远程服务器的最终数据一致。常见的解决思路包括:

  • 写回策略(Write-Back):离线时先将修改保存在本地队列,恢复网络后批量同步。
  • 版本向量(Version Vector):每个资源附带版本戳,同步时比较版本差异解决冲突。
  • 到期强制刷新:离线时间过长时,强制清除过期缓存,要求用户重新联网加载。

1.3 Cache-Control 指令

HTTP Cache-Control 响应头是服务器控制缓存行为的主要手段。以下指令直接影响离线缓存的命中/失效/一致性策略:

指令含义对离线缓存的影响
max-age=seconds资源从生成起有效秒数离线期间若在有效期内,可安全使用;过期后视为失效
no-cache每次使用前需向服务器验证是否更新离线时无法验证,缓存不可用(退化至无缓存)
no-store禁止任何形式的缓存离线缓存无法保存该资源
must-revalidate过期后必须与服务器重新验证离线时若网络不可达,即使缓存存在也不允许使用(一致性要求高)
stale-while-revalidate过期后允许使用旧缓存,同时在后台异步更新离线期间若更新请求失败,仍可暂时使用旧数据,提升可用性
常见错误:为追求高命中率,将静态API的 max-age 设置得极大(例如30天)。一旦服务器资源变更,客户端将长期使用错误数据,且离线模式下的冲突更难解决。建议结合 immutable 或 stale-while-revalidate 指令平衡。

1.4 核心概念关系图

下图展示了离线缓存各核心概念之间的逻辑关系与数据流向:

离线缓存核心概念关系图 客户端请求 缓存命中 缓存失效 离线模式 一致性检查 Cache-Control 说明:实线箭头表示缓存命中或失效后的直接路径;虚线箭头表示即使在缓存命中情况下, 也可通过一致性检查决定是否使用本地数据。Cache-Control 指令决定了缓存的过期策略与验证行为。

1.5 代码示例:服务端设置 Cache-Control

下面以 Node.js + Express 为例,演示如何为 API 响应设置 Cache-Control 指令,使其支持离线缓存(max-age + stale-while-revalidate):

const express = require('express');
const app = express();

app.get('/api/catalog', (req, res) => {
    // 假设从数据库获取商品列表
    const data = { items: [...] };
    // 允许缓存 5 分钟,过期后仍可使用旧数据 60 秒,同时后台更新
    res.set('Cache-Control', 'public, max-age=300, stale-while-revalidate=60');
    res.json(data);
});

app.listen(3000, () => console.log('API running on port 3000'));

1.6 调试与常见错误

  • 缓存未生效:检查服务端是否正确设置了 Cache-Control 头,以及客户端(如浏览器、Service Worker)是否拦截了缓存策略。
  • 离线数据过老:如果使用 stale-while-revalidate 但未设置 stale-if-error,离线时网络不可达将无法获得任何数据。
  • 一致性冲突:不同客户端同时离线修改同一资源,恢复网络后同步时出现版本冲突。务必引入版本号或时间戳机制。

1.7 性能与稳定性优化

优化要点:
  • 对读多写少的 API 使用较长的 max-age 并配合 must-revalidate 降低服务器压力。
  • 结合 Service Worker 实现离线缓存策略(例如“缓存优先,网络回退”),在用户无感的情况下提升首屏加载速度。
  • 监控缓存命中率与失效比例,动态调整过期时间——命中率长期低于 30% 的 API 应考虑缩短过期或移除缓存。