Skip to content

缓存(Caching)

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公开。 典型场景如下。

缓存命中

在理想情况下,缓存可以满足请求,而无需对网络进行任何有条件调用。 这将跳过正常的事件,如域名解析、连接网络、下载响应Body等。

根据HTTP RFC的建议,缓存文档的最大可用时间可基于服务器返回的“Last-Modified”时间加上文档已缓存时长(age)的10%。 默认过期日期不用于包含查询(query)的URI。

  • CallStart
  • CacheHit
  • CallEnd

缓存未命中

在缓存未命中下,可以看到正常的请求事件,但是另一个事件显示缓存的存在。 如果尚未从网络中读取该项目,不可访问或基于响应缓存标头已超过其生命周期,则缓存未命中将是典型的。

  • CallStart
  • CacheMiss
  • ProxySelectStart
  • … Standard Events …
  • CallEnd

条件缓存命中

当缓存标志需要检查缓存结果仍然有效时,将接收到早期的cacheConditionalHit事件,然后是缓存命中或未命中。 关键是,在缓存命中场景中,服务器不会发送响应正文。

响应将具有非空的 cacheResponsenetworkResponse。 只有当响应代码为HTTP/1.1 304未修改时,cacheResponse才会用作顶级响应。

  • CallStart
  • CacheConditionalHit
  • ConnectionAcquired
  • … Standard Events…
  • ResponseBodyEnd (0 bytes)
  • CacheHit
  • ConnectionReleased
  • CallEnd

缓存目录

缓存目录必须由单个实例独占。

可以在不再需要缓存时将其删除。 但是,这可能会导致本来应该在应用程序重新启动之间持续存在的缓存策略失效。

cache.delete()

修剪缓存

可以使用evictAll修剪整个缓存以暂时清除空间。

cache.evictAll()

也可以使用URL迭代器删除单个项目。 这和用户在浏览器中通过拉刷新一类动作发起强制刷新相似。

    val urlIterator = cache.urls()
    while (urlIterator.hasNext()) {
      if (urlIterator.next().startsWith("https://www.google.com/")) {
        urlIterator.remove()
      }
    }

故障排除

  1. 有效的可缓存响应没有被缓存

确保你的响应读取是完整的,因为除非它们被完整读取,否则取消或停止的响应都不会被缓存。

覆盖正常缓存行为

请参见缓存文档。 https://square.github.io/okhttp/4.x/okhttp/okhttp3/-cache/