我正在使用以下代码从TfL下载一些数据。

NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]
                                                      delegate:self delegateQueue:[NSOperationQueue mainQueue]];

NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://api.tfl.gov.uk/StopPoint/490012211N/Arrivals"]];

[[session dataTaskWithRequest:req
        completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
            if (!error) {
                NSLog(@"Loaded Succesfully");
            }
            NSCachedURLResponse *resp = [[NSURLCache sharedURLCache] cachedResponseForRequest:req];
            if (resp) {
                NSLog(@"Response in cache");
            }
            [[session dataTaskWithRequest:req
                        completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                            if (!error) {
                                NSLog(@"Loaded Sucessfully again");
                            }
                        }] resume];
        }] resume];

响应的缓存控制标头字段为public, must-revalidate, max-age=5, s-maxage=10,这似乎意味着即使第二个请求在max-age给出的5秒钟内,服务器也将发送请求。如果我使用Charles编辑响应并删除必须重新验证的内容,那么上面的代码只会向服务器发送一次请求。

HTTP / 1.1规范说

该缓存在过期后就不能再使用该条目来响应
后续请求,而无需先与原始服务器重新验证。

for must-revalidate,但是似乎iOS似乎忽略了“过时”部分?并以must-revalidate表示忽略最大年龄。那么与将字段设置为根本不缓存有何不同。我已经检查过,并且请求/响应已添加到缓存中,所以must-revalidate似乎使缓存变得肿,因为它将永远不会使用它,但仍将其添加到缓存中?

那么服务器将must-revalidatemax-age结合使用是不正确的,还是iOS处理must-revalidate的方式不正确?

有没有办法拦截响应,以便我可以删除must-revalidate? NSURLProtocol似乎很有用,但我只能看到如何修改请求,而不是响应。

最佳答案

如果使用NSURLProtocol,则可以发出一个新请求(一定要对其进行标记,以免再次修改它),然后在响应上,可以基于旧请求创建一个新的响应对象,并将修改后的响应发送给客户端。我不确定这是否足以解决您的问题。

但是,更好的解决方案(请阅读“实现起来更直接得多”)可能是将NSURLCache对象子类化,并使用您的自定义子类作为共享缓存(对于NSURLConnection和NSURLSession共享会话)或作为每个会话缓存(对于其他NSURLSession会话)。

10-08 20:03