【问题标题】:NSURLCache caching random responses that should not be cachedNSURLCache 缓存不应该被缓存的随机响应
【发布时间】:2013-09-05 09:05:43
【问题描述】:

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

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


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


更多背景信息:

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

【问题讨论】:

  • 设备和服务器之间不可能存在时钟同步问题? Specs 说在这种情况下客户端的行为是不确定的(由客户端做适当的事情)。您是否也尝试过检测afnetworking 代码只是为了获得更多洞察力?
  • 时间问题是我的第一个想法,但我找不到可重复的场景(它非常随机地发生)。无论如何,它发生在具有适当时间的设备上,服务器端也是正确的,所以它似乎不是这样 :( 感谢您的提示!

标签: ios caching nsurlconnection afnetworking nsurlcache


【解决方案1】:

NSURLCache 如何与 NSURLConnection 一起决定一个 特定请求不需要上线时...

RFC 2616 第 13.2 节说:

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

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

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

【讨论】:

  • 这是迄今为止最好的答案。它不能解决问题,但至少 RFC 2616 上的段落解释了我正在经历的事情。谢谢!
【解决方案2】:

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

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

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

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

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

【讨论】:

  • 感谢 Vailbhav。正如我所说,这实际上是缓存的问题,但不是没有缓存,而是相反:不应该缓存的东西被缓存了。此外,它保存在磁盘上,但这是意料之中的,因为在 iOS5 上,神经缓存保存在磁盘上。
【解决方案3】:

请确保您的 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

【讨论】:

  • 谢谢,但正如解释的那样,问题不在于他的信息不是偶然的,而是完全相反:它在不应该缓存的时候缓存。除了 iOS5 缓存在磁盘上,所以实现我自己的类可能不会有太大帮助,尽管我会尝试一下。
  • @shoeb : 仅供参考,因为 ios5 NSURLCACHE 让你选择磁盘或内存,并分配大小。
  • 感谢我了解 iOS5 的功能,但我制作的课程也可以让您从应用程序的主包中返回缓存..
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-12-08
  • 1970-01-01
  • 1970-01-01
  • 2014-09-27
  • 2014-08-14
  • 2022-10-02
  • 2013-12-08
相关资源
最近更新 更多