7

我正在实现一个应用程序,它对我们也控制的 rest-api 进行大量网络调用。最近我们决定在服务器端引入缓存头,以节省一些宝贵的网络和服务器时间。由于我们事先不知道数据的有效期有多长,所以我们没有发送Cache-control: max-ageExpires标头,我们所做的只是将Last-Modified标头与 a 一起发送E-tag,因此我们总是访问服务器,但大多数时候响应非常快,带有 a 304. 起初一切似乎都很好,许多请求都被缓存了。但是,由于缓存,我在应用程序上遇到了一些随机数据错误。

出于某种原因,我无法理解,在某些时候,请求被本地缓存并用作“更新”数据而不会命中服务器,而实际上它们不是。问题一直存在,直到一段时间过去。然后一切都再次正常进入服务器,就像它在cache-control标题中的行为一样,但没有它!。所以,我的问题是:


当原始请求没有附带或标头时NSURLCache,如何NSURLConnection确定特定请求不需要上线?有没有人经历过类似的效果?以及如何在不删除整个缓存的情况下解决它?Cache-control: max-ageExpires


更多背景信息:

  • 我正在使用AFNetworking,但它依赖于NSURLConnection所以我认为它不会改变任何东西
  • 使用的缓存是默认[NSURLCache sharedURLCache]实例
  • 这是一个GET请求,当我检查缓存响应中的标头时,我得到的是:

    po [response allHeaderFields]

    "Access-Control-Allow-Headers" = "Content-Type";
    "Access-Control-Allow-Methods" = "GET, POST, DELETE, PUT";
    "Access-Control-Allow-Origin" = "*";
    Connection = "keep-alive";
    "Content-Encoding" = gzip;
    "Content-Length" = 522;
    "Content-Type" = "application/json";
    Date = "Mon, 02 Sep 2013 08:00:38 GMT";
    Etag = "\"044ad6e73ccd45b37adbe1b766e6cd50c\"";
    "Last-Modified" = "Sat, 31 Aug 2013 10:36:06 GMT";
    Server = "nginx/1.2.1";
    "Set-Cookie" = "JSESSIONID=893A59B6FEFA51566023C14E3B50EE1E; Path=/rest-api/; HttpOnly";
    
  • 我无法预测或重现错误何时发生,因此依赖于删除缓存的解决方案不是一种选择。

  • 我正在使用 iOS5+
4

3 回答 3

4

NSURLCache 和 NSURLConnection 如何决定某个特定请求在什么时候不需要上线...

RFC 2616的第 13.2 节说:

由于原始服务器并不总是提供明确的过期时间,HTTP 缓存通常会分配启发式过期时间,使用使用其他标头值(例如 Last-Modified 时间)的算法来估计合理的过期时间。HTTP/1.1 规范没有提供特定的算法,但确实对其结果施加了最坏情况的约束。由于启发式过期时间可能会损害语义透明度,因此应谨慎使用,我们鼓励源站服务器尽可能提供明确的过期时间。

因此,即使您没有为数据提供特定的生命周期,URL 加载系统也有可能决定缓存的数据“足够新鲜”。

为了获得最佳结果,您应该尝试在响应标头中提供特定的生命周期。如果添加这样的标头是不可能的,也许您可​​以更改请求。if-modified-since或者cache-control每个都可以帮助您避免缓存数据。

于 2013-09-10T10:39:38.940 回答
2

根据声明“在某些时候请求被本地缓存并用作“更新”数据而不会命中服务器“我很确定您的请求是内存缓存的。

NSURLCache 将数据缓存在内存中。不在磁盘上。所以让我解释一下你可能会发生什么。

您启动应用程序。进行 Web 服务调用它会从服务器获取数据,您再次调用它并从内存中获取响应而不调用服务器并向您显示结果。

您离开应用程序一段时间或重新启动应用程序。它检查数据是否在内存中。如果它不可用,则它再次调用服务器并重复相同的行为。

我建议您编写自己的磁盘缓存,而不是依赖 NSURLConnection 和 NSUrlCache。因为苹果的一些缓存策略仍然没有实现。

于 2013-09-10T08:12:01.830 回答
2

请确保您的 NSURLRequest 缓存策略设置为 NSURLRequestReturnCacheDataElseLoad

在这里,如果您在 AFHTTPClient.m 中使用 AFNetworking,您可以覆盖该方法

- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
                                  path:(NSString *)path
                            parameters:(NSDictionary *)parameters

用这个替换第 470 行

    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:15];

您实际上在做的是告诉请求在服务器未更新时加载缓存..如果服务器已更新,那么它将忽略缓存并从服务器下载内容

仅供参考:NSURLCache 将数据存储在内存中。如果你想将数据存储在磁盘中,你可以在这里使用我的类

https://github.com/shoeb01717/Disc-Cache-iOS

于 2013-09-10T15:53:52.047 回答