URLSession 缓存未按记录工作 - 我做错了什么?

mlu*_*own 10 caching ios swift urlsession

根据文档,如果使用默认值,useProtocolCachePolicy逻辑如下:

  1. 如果该请求不存在缓存的响应,则 URL 加载系统将从原始源获取数据。
  2. 否则,如果缓存的响应没有指示每次都必须重新验证,并且缓存的响应不是过时的(超过其过期日期),则 URL 加载系统将返回缓存的响应。
  3. 如果缓存的响应已过时或需要重新验证,则 URL 加载系统会向原始源发出 HEAD 请求,以查看资源是否已更改。如果是,则 URL 加载系统从原始源获取数据。否则,它返回缓存的响应。

然而,我的实验(见下文)表明这是完全错误的。即使响应被缓存,它也永远不会被使用,也不会发出HEAD任何请求。

设想

我正在向一个返回的 URL 发出请求,ETag并且Last-Modified标头永远不会改变。我至少发出过一次请求,因此响应已被缓存(我可以通过查看 iOS 模拟器上应用程序的缓存数据库来验证这一点)

使用useProtocolCachePolicy(默认)

如果我将URLSessionwith设置为URLSessionConfiguration,则响应将被缓存(我可以在缓存数据库中看到它),但缓存的响应永远不会被使用。对同一 URL 的重复请求始终会发出不带或标头的新请求,因此服务器始终返回 HTTP 200 和完整响应。缓存的响应将被忽略。requestCachePolicyuseProtocolCachePolicyGET If-None-MatchIf-Modified-Since

用于reloadRevalidatingCacheData每个URLRequest

如果我将每个cachePolicy设置为,那么我会看到缓存正在运行。每次发出请求时,都会发出请求,并将和标头分别设置为缓存响应的和标头的值。由于没有任何变化,服务器以 进行响应,并将本地缓存的响应返回给调用者。 URLRequestreloadRevalidatingCacheDataGETIf-None-MatchIf-Modified-SinceETagLast-Modified304 Not Modified

仅使用reloadRevalidatingCacheDataURLSessionConfiguration

如果我只requestCachePolicy = . reloadRevalidatingCacheDataURLSessionConfiguration(而不是在每个URLRequest)上设置,那么当应用程序启动时,只有第一个请求使用缓存标头并获取304 Not Modified响应。后续请求是普通的 GET 请求,没有任何缓存标头。

结论

所有其他缓存策略设置基本上都是“仅使用缓存数据”或“从不使用缓存”的变体,因此与此处无关。

存在像文档声称的那样URLSession发出请求的情况HEAD,也不存在仅使用缓存数据而不根据原始响应中的到期日期信息重新验证的情况。

我将使用的解决方法是对每个cachePolicy = .reloadRevalidatingCacheData进行设置以获得一定程度的本地缓存,因为响应仅返回标头而不返回数据,因此可以节省网络流量。 URLRequest304 Not Modified

如果有人有更好的解决方案,或者知道如何URLSession按照记录进行工作,那么我很想知道。