Alamofire 使用可配置缓存

Alamofire use configurable Caching

我正在使用 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
   )

如果后端正在 return 进行适当的缓存 header,您希望将其限制在一定时间,在请求中添加 Cache-Control: max-age= header可能有用。

如果后端没有 return 适当的缓存 header,使用 ResponseCacher 是可行的方法。您将修改 CachedURLResponseresponse 以包含正确的 Cache-Control header.

详细说明乔恩的回答,实现你想要的最简单的方法是让后端声明这个端点的缓存语义,然后确保在客户端, URLSession 使用 URLCache(这可能是默认的)并让 URLSession 和后端完成剩下的工作。 不过,这需要您控制后端!

更详细的答案:

这只是一个示例,服务器如何 return 具有声明的缓存语义的响应:

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)

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

例如,

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

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

Age header 是一个提示,表明响应实际上是从客户端和源服务器之间存在的缓存中传递的。 age 是此数据年龄的估计 - 从在源上创建到交付的持续时间。

我不想详细说明每个 header 的确切含义以及客户端和服务器应如何根据 HTTP 运行,因为这是一个非常激烈的话题,但是 基本上,当您定义端点时,只需 定义 returned 数据 .[=18= 的“新鲜度”的持续时间]

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

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

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

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

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

每个细节都值得在 SO 上进行专门的问答。