繁体   English   中英

NSURLCache与NSURLSession一起不尊重:Cache-Control:max-age:86000,private,must-revalidate

[英]NSURLCache, together with NSURLSession, does not respect: Cache-Control: max-age:86000, private, must-revalidate

在AppDelegate.m中,我配置了:

NSURLCache *sharedURLCache = [[NSURLCache alloc] initWithMemoryCapacity:20 * 1024 * 1024 diskCapacity:100 * 1024 * 1024 diskPath:@"FhtHttpCacheDir"];

然后是http请求:

- (void) testRestfulAPI{
    NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:config];

    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://192.168.0.223:8000/v1/topictypes"]];

    [request setHTTPMethod:@"GET"];
    [request setValue:@"application/json" forHTTPHeaderField:@"Accept"];

    NSError *error = nil;
    if (!error) {
        NSURLSessionDataTask *downloadTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
            if (!error) {
                NSHTTPURLResponse *httpResp = (NSHTTPURLResponse*) response;
                if (httpResp.statusCode == 200) {
                    NSDictionary* json = [NSJSONSerialization
                                          JSONObjectWithData:data
                                          options:kNilOptions
                                          error:&error];
                    NSLog(@"JSON: %@", json);
                }
            }
        }];
        [downloadTask resume];
    }
}

它第一次请求时,它获得了带有Etag + Cache-Control标头的HTTP 200。 没问题。

在此输入图像描述

如果我没有错, Cache-Control: must-revalidate, max-age=86400, private将告诉NSURLCache在24小时内将缓存视为新鲜,并且在接下来的24小时内不会进行任何网络呼叫。

但事实并非如此,第二次发出http请求时,它实际上发出了If-None-Match标头并返回HTTP 304。

在此输入图像描述

在我看来,NSURLCache部分工作。 它可以缓存响应,但它不遵循RFC 2616语义,因为Apple doc 在此描述。 仅供参考,我没有更改缓存策略,因此它使用默认的NSURLRequestUseProtocolCachePolicy

我用Google搜索了一天以上的类似问题和其他经验丰富的类似问题,但我没有找到任何解决方案。 一些人在AFNetworking的github问题上询问了同样的问题,但是作者关闭了这个问题,因为它与AFNetworking 在这里这里没有直接关系。

各种相关的stackoverflow帖子也没有帮助我。

问题

问题是使用Cache-Control响应指令必须重新验证。

通过省略must-revalidate,就我的理解而言,你已经对你的用例有了完美的定义:

Cache-Control: max-age=86400, private

这可以控制所请求资源被视为新鲜的时间。 经过这段时间后,答案不应再直接来自缓存,而应联系服务器以验证后续请求。 在您的情况下,由于服务器提供ETag,iOS会向服务器发送带有If-None-Match标头的请求。

验证

为了检查这一点,我使用了没有NSURLCache设置的testRestfulAPI方法,并在服务器端配置了最长60秒的时间,因此我不必等待一天来检查结果。

之后,我每秒触发一次testRestfulAPI。 我总是从缓存中得到所需的结果。 Charles显示数据必须来自缓存,因为服务器没有联系60秒。

使用Charles进行验证

RFC 7234

以下是RFC 7234(废弃RFC 2616)的引用,见5.2.2.1。 它指出:

必须重新验证指令对于支持某些协议功能的可靠操作是必需的。 在所有情况下,缓存必须遵守必须重新验证的指令; 特别是,如果缓存因任何原因无法到达原始服务器,它必须生成504(网关超时)响应。

当且仅当无法验证对表示的请求可能导致不正确的操作(例如无声的未执行的金融交易)时,服务器才应使用必须重新验证的指令。

阅读完之后,如果您将自己置于缓存开发人员的视野中,您可以想象当看到必须重新验证时,始终会联系原始服务器,并且只会忽略任何其他指令(如max-age)。 在我看来,缓存通常在实践中显示出这种行为。

第5.2.2.1章还有另一节。 我不会隐瞒,其内容如下:

“must-revalidate”响应指令表明,一旦它变得陈旧,高速缓存不得使用响应来满足后续请求,而无需在源服务器上成功验证。

这通常被解释为通过指定max-age和must-revalidate,您可以确定内容何时过时(在max-age seconds之后),然后它必须在源服务器上验证才能提供内容。

然而,在实践中,由于上面给出的原因,似乎必须重新验证总是导致对源服务器上的每个请求的验证。

尝试更改这些行

NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:config];

对此:

NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
config.urlCache = sharedURLCache; // make sure sharedURLCache is accessible from here
NSURLSession *session = [NSURLSession sessionWithConfiguration:config];

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM