NSURLCache - 参数不起作用的GET请求的磁盘缓存

问题描述:

我想使用NSURLCache缓存一些HTTP请求到磁盘。在使用AFNetworking进行一些测试并且不能工作之后,我使用NSURLRequest创建了一个简单示例。NSURLCache - 参数不起作用的GET请求的磁盘缓存

我初始化的AppDelegate中这样的高速缓存,内存大小设置为0,迫使它总是到磁盘:

NSUInteger sz = 1024*1024*20; 
NSURLCache *cache = [[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:sz diskPath:nil]; 
[NSURLCache setSharedURLCache:cache]; 

我用下面的代码来存储响应:

NSURLCache * urlCache = [NSURLCache sharedURLCache];

NSString *urlString = @"http://localhost:8000/cities/api/cities/?lang=en"; 
NSHTTPURLResponse *response = nil; 
NSError *error = nil; 

NSURL *finalUrl = [NSURL URLWithString:urlString]; 
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:finalUrl]; 
request.cachePolicy = NSURLRequestReturnCacheDataElseLoad; 

NSData *data = nil; 

data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; 

NSCachedURLResponse *cachedResponse = [[NSCachedURLResponse alloc] initWithResponse:response data:data userInfo:nil storagePolicy:NSURLCacheStorageAllowed]; 
[urlCache storeCachedResponse:cachedResponse forRequest:request]; 

我请求具有HTTP头缓存控制,如:

响应[“缓存控制”] =“最大年龄= 36000,公共”

我看到的响应被缓存在文件Cache.db中。

后来,在一次执行,甚至在同一个,我用下面的代码试图从缓存中响应:

NSCachedURLResponse *cachedResponse = [urlCache cachedResponseForRequest:request]; 
response = cachedResponse.response; 
data = cachedResponse.data; 

的问题是,cachedResponse总是空当该请求具有GET参数。如果请求是“http://localhost:8000/cities/api/cities/”,则结果稍后存储和恢复。但是,当它具有GET参数时,阻止该方法[NSURLCache cachedResponseForRequest:request]找到请求。

给予此,我子类NSURLCache和实现像这样的方法:

- (id)initWithMemoryCapacity:(NSUInteger)memoryCapacity diskCapacity:(NSUInteger)diskCapacity diskPath:(NSString *)path { 
self = [super initWithMemoryCapacity:memoryCapacity diskCapacity:diskCapacity diskPath:path]; 
if (self) { 
    NSArray *docPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); 
    NSString *dir = (NSString*)[docPaths objectAtIndex:0]; 
    dir = [dir stringByAppendingString:@"/uk.co.airsource.TestURLCache/nsurlcache"]; 
    NSString *path = [dir stringByAppendingFormat:@"/Cache.db"]; 
    self.db = [[FMDatabase alloc] initWithPath:path]; 
    [self.db open]; 
    int o = 4; 
} 
return self; 

}

- (NSCachedURLResponse *) cachedResponseForRequest:(NSURLRequest *)request { 
NSCachedURLResponse *cachedURLResponse = [super cachedResponseForRequest:request]; 
if (cachedURLResponse == nil && [request.HTTPMethod isEqualToString:@"GET"]) { 
    //[db executeQuery:@"select * from test where a = ?", @"hi'", nil]; 
    NSLog(@"%@", request.URL.absoluteString); 
    FMResultSet *cfurl_cache_response = [self.db executeQuery:@"select * from cfurl_cache_response where request_key = ? limit 1", request.URL.absoluteString, nil]; 
    if ([cfurl_cache_response next]) { 
     id entry_ID = [cfurl_cache_response objectForColumnName:@"entry_ID"]; 
     [cfurl_cache_response close]; 
     if (entry_ID != [NSNull null]) { 
      FMResultSet *cfurl_cache_blob_data = [self.db executeQuery:@"select * from cfurl_cache_blob_data where entry_ID = ? limit 1", entry_ID, nil]; 
      if ([cfurl_cache_blob_data next]) { 
       id response_object = [cfurl_cache_blob_data objectForColumnName:@"response_object"]; 
       [cfurl_cache_blob_data close]; 
       FMResultSet *cfurl_receiver_data = [self.db executeQuery:@"select * from cfurl_cache_receiver_data where entry_ID = ? limit 1", entry_ID, nil]; 
       if ([cfurl_receiver_data next]) { 
        id receiver_data = [cfurl_receiver_data objectForColumnName:@"receiver_data"]; 
        [cfurl_receiver_data close]; 
        if (response_object != [NSNull null] && receiver_data != [NSNull null] && response_object && receiver_data) { 
         NSURLResponse *urlResponse = [[NSURLResponse alloc] initWithURL:request.URL MIMEType:[[request allHTTPHeaderFields] objectForKey:@"Accept"] expectedContentLength:[(NSData *)response_object length] textEncodingName:nil]; 
         cachedURLResponse = [[NSCachedURLResponse alloc] initWithResponse:urlResponse data:receiver_data userInfo:nil storagePolicy:NSURLCacheStorageAllowed]; 
        } 
       } 
      } 
     } 
    } 
} 
return cachedURLResponse; 

}

与参数的GET请求下这种情况下,它确实遵循直到获得之前缓存的NSURLResponse。

关于为什么当请求具有GET参数时它不能正常工作?

DB with the 2 requests stored

最后我overrided NSURLCache能够达到什么样的我一直在寻找:

  1. GET请求(带有参数)被缓存到磁盘
  2. 请求将缓存而“高速缓存控制最大年龄”的值表示,它没有过期,并且在过期之后再次将服务器,存储新的响应和重新开始
  3. 到期时间。如果下线,总回报响应(如果存在)从缓存中

NTURLCache - overrides NSURLCache

我认真地想,这是不是在iOS的8.1 ​​

+0

我得到了和你一样的问题,任何更新? – NickYu 2015-04-20 10:09:58

+0

我通过继承NSURLCache来解决它,您可以在我的响应中的链接中找到该项目。 – jcardenete 2015-04-20 12:01:28

+1

thx队友,它的惊人 – NickYu 2015-04-21 08:16:40

的问题似乎与不指定内存容量,如果指定内存容量如下,

我在这里指定为1 MB大小的内存容量

[[NSURLCache alloc] initWithMemoryCapacity:1*1024*1024 diskCapacity:sz diskPath:nil]; 

它会工作,在我看来好像内存容量是需要的,不管是多少小容量,但不能为空。然后,你就可以提取存储缓存如下,

NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request]; 
response = cachedResponse.response; 
data = cachedResponse.data; 
+0

我重新启动一切,就像你说的那样正常工作的问题,但同样的事情正在发生。响应被存储在数据库中。然后关闭应用程序并再次打开它,当我尝试从缓存中获取响应时,它返回nil。 – jcardenete 2015-02-12 20:11:05

+0

在我看来,它好像根本没有去检查Cache.db中的磁盘缓存 – jcardenete 2015-02-12 20:48:22

+0

您能否确认您的本地URL是否返回内容? – ldindu 2015-02-12 20:52:49