【问题标题】:Alamofire use configurable CachingAlamofire 使用可配置缓存
【发布时间】:2021-04-17 13:54:09
【问题描述】:

我正在使用 Alamofire 5,并且要求应该缓存一些 GET 请求。如果数据早于 20 分钟,则应点击真正的 API。

我发现是使用 ResponseCacher。但我看不到配置单个请求的方法,需要一些建议。

let responseCacher = ResponseCacher(behavior: .modify { _, response in
          let userInfo = ["date": Date()]
          return CachedURLResponse(
            response: response.response,
            data: response.data,
            userInfo: userInfo,
            storagePolicy: .allowed)
        })
let configuration = URLSessionConfiguration.af.default

private override init() {
   configuration.timeoutIntervalForRequest = 10
        configuration.requestCachePolicy = .reloadRevalidatingCacheData
   Session(
      configuration: configuration,
      serverTrustManager: ServerTrustManager(evaluators: evaluators),
      cachedResponseHandler: responseCacher
   )

【问题讨论】:

  • 如果可以在后端指定返回数据的“新鲜度”语义,您的用例可以在客户端使用本地 URL 缓存并遵循 HTTP 协议以实际零代码实现,后端发送相应的响应头。这通常是这种情况,也强烈建议这样做,而不是在客户端实现任何自定义缓存逻辑。如果您需要更多帮助,我很乐意在答案中提供更多详细信息。
  • 是的 - 我会非常感兴趣如何使用 ResponseCacher 或任何需要的东西来完成正确的实现。我被要求创建一个 CoreData 数据库并在那里缓存数据,但我认为这不是你写的方式。
  • 您可以在您的应用程序中实现基于 URL 缓存的“离线”支持,并结合一些填充 URL 缓存的后台“预取”功能。我们已经在我们的应用程序中做到了这一点,并且效果很好。你当然可以使用 CoreData 来缓存你的数据。是否要使用 URLCaches 或 CoreData 的决定当然取决于其他几个要求。关于缓存,HTTP 缓存非常强大,而且(几乎)是免费的,因为在 URLSession 和后端实现。

标签: ios swift alamofire


【解决方案1】:

如果后端返回正确的缓存标头,并且您希望将其限制在一定时间内,则在请求中添加 Cache-Control: max-age= 标头可能会起作用。

如果后端没有返回正确的缓存头,使用ResponseCacher 是要走的路。您将修改 CachedURLResponseresponse 以包含正确的 Cache-Control 标头。

【讨论】:

    【解决方案2】:

    详细说明 Jon 的答案,实现您想要的最简单的方法是让后端声明此端点的缓存语义,然后确保在客户端, URLSession 使用 URLCache (这可能是默认值)并让 URLSession 和后端完成其余的工作。 不过,这要求您可以控制后端!

    更详细的答案:

    这里只是一个例子,服务器如何返回带有声明缓存语义的响应:

    URL: https://www.example.com/ Status Code: 200
        Age: 238645
        Cache-Control: max-age=604800
        Date: Tue, 12 Jan 2021 18:43:58 GMT
        Etag: "3147526947"
        Expires: Tue, 19 Jan 2021 18:43:58 GMT
        Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
        Vary: Accept-Encoding
        x-cache: HIT
    
        Accept-Ranges: bytes
        Content-Encoding: gzip
        Content-Length: 648
        Content-Type: text/html; charset=UTF-8
        Server: ECS (dcb/7EC7)
    

    此服务器从字面上输出服务器可以声明的有关缓存的全部内容。前八个标头(从Agex-cache)声明缓存。

    例如,

    Cache-Control: max-age=604800 声明数据的新鲜度 等于 604800 秒。有了服务器创建数据的日期,客户端现在可以检查数据是否仍然“新鲜”。

    Expires: Tue, 19 Jan 2021 18:43:58 GMT 表示完全相同的意思,它声明 when 指定挂钟的数据已过时。这与上面的声明是多余的,但它在 HTTP 中非常清楚地定义了客户端应该如何处理它。

    有一个Age 标头是一个提示,响应实际上是从存在于客户端和源服务器之间的缓存中传递的。 age 是对这个数据的年龄的估计——从它在源上创建到交付的持续时间。

    我不会详细说明每个标头的确切含义以及客户端和服务器应如何根据 HTTP 进行操作,因为这是一个非常激烈的话题,但基本上要做的就是当你定义一个端点时,只是为了定义返回数据的“新鲜度”的持续时间

    全部详情:Hypertext Transfer Protocol (HTTP/1.1): Caching

    一旦你想出了一个好的持续时间,Web 应用程序框架(如 Rails、SpringBoot 等)就可以在开箱即用地声明缓存语义方面提供很大帮助。然后 Web 应用程序框架将在响应中输出相应的标头 - 或多或少“自动”。

    URLSession 会根据 HTTP 协议自动做正确的事情(嗯,差不多)。也就是说,它将响应存储在缓存中,当您执行后续请求时,它首先在缓存中查找合适的响应,如果仍然给出数据的“新鲜度”,则返回该响应。

    如果缓存的数据太旧(根据给定的响应头和当前数据和时间),它将尝试通过向源服务器发送请求来获取新数据。任何上游缓存或最终的原始服务器可能会返回新数据。您的 URLSession 数据任务透明地执行所有这些操作,而不会让您知道数据是来自缓存还是原始服务器。老实说,在大多数情况下,您不需要知道它。

    根据 HTTP 声明缓存语义非常强大,它通常应该适合您的需求。此外,客户端可以通过指定某些请求标头来定制其需求,例如允许返回甚至是过时的数据或忽略任何缓存的值等等。

    每个细节都值得专门针对 SO 进行问答。

    【讨论】:

      猜你喜欢
      • 2017-07-14
      • 2012-10-22
      • 2017-12-12
      • 1970-01-01
      • 2015-04-02
      • 1970-01-01
      • 1970-01-01
      • 2015-08-24
      • 2010-09-09
      相关资源
      最近更新 更多