缓存¶
OkHttp 实现了一个可选的、默认关闭的缓存。OkHttp 旨在实现符合 RFC 且实用的缓存行为,在存在歧义时遵循 Firefox/Chrome 等常见真实世界浏览器和服务器的行为。
基本用法¶
private val client: OkHttpClient = OkHttpClient.Builder()
.cache(Cache(
directory = File(application.cacheDir, "http_cache"),
// $0.05 worth of phone storage in 2020
maxSize = 50L * 1024L * 1024L // 50 MiB
))
.build()
EventListener 事件¶
缓存事件通过 EventListener API 公开。典型场景如下所示。
缓存命中¶
在理想情况下,缓存可以直接满足请求,无需进行任何条件性的网络调用。这将跳过 DNS、连接网络和下载响应体等正常事件。
根据 HTTP RFC 的建议,文档的最大有效期默认为其在服务时基于“Last-Modified”的年龄的 10%。包含查询的 URI 不使用默认过期日期。
- CallStart
- CacheHit
- CallEnd
缓存未命中¶
在缓存未命中时,会看到正常的请求事件,但会额外出现一个事件表明缓存的存在。如果项目尚未从网络读取、无法缓存,或者已超出基于响应缓存头指定的生命周期,则通常会出现缓存未命中。
- CallStart
- CacheMiss
- ProxySelectStart
- … 标准事件 …
- CallEnd
条件缓存命中¶
当缓存标志要求检查缓存结果是否仍然有效时,会首先接收到一个 cacheConditionalHit 事件,然后是缓存命中或未命中。至关重要的是,在缓存命中场景下,服务器不会发送响应体。
响应将具有非空的 cacheResponse
和 networkResponse
。仅当响应代码是 HTTP/1.1 304 Not Modified 时,才会将 cacheResponse 用作顶层响应。
- CallStart
- CacheConditionalHit
- ConnectionAcquired
- … 标准事件…
- ResponseBodyEnd (0 字节)
- CacheHit
- ConnectionReleased
- CallEnd
缓存目录¶
缓存目录必须由单个实例独占。
可以在不再需要时删除缓存。然而,这可能会破坏缓存的目的,因为缓存旨在在应用程序重启之间持久化。
cache.delete()
修剪缓存¶
可以使用 evictAll 临时清理整个缓存以释放空间。
cache.evictAll()
可以使用 urls 迭代器移除单个项目。这通常在用户通过下拉刷新等操作强制刷新后进行。
val urlIterator = cache.urls()
while (urlIterator.hasNext()) {
if (urlIterator.next().startsWith("https://www.google.com/")) {
urlIterator.remove()
}
}
故障排除¶
- 有效的可缓存响应未被缓存
请确保您完整地读取响应,因为除非响应被完整读取、取消或停止,否则不会被缓存。
覆盖正常的缓存行为¶
请参阅缓存文档。 https://square.ac.cn/okhttp/4.x/okhttp/okhttp3/-cache/