NSURLCache - 参数不起作用的 GET 请求的磁盘缓存
NSURLCache - Disk caching for GET request with parameters not working
我正在尝试使用 NSURLCache 将一些 HTTP 请求缓存到磁盘。在使用 AFNetworking 进行了一些测试但没有工作之后,我使用 NSURLRequest 创建了一个简单的示例。
我像这样初始化 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 Header Cache-Control 比如:
响应['cache-control'] = 'max-age=36000, public'
我看到响应缓存在文件 Cache.db.
中
后来,在下一次甚至同一次执行中,我使用以下代码尝试从缓存中获取响应:
NSCachedURLResponse *cachedResponse = [urlCache cachedResponseForRequest:request];
response = cachedResponse.response;
data = cachedResponse.data;
问题是当请求上有 GET 参数时,cachedResponse 总是 null 。如果请求是“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 参数时它不能正常工作有什么想法吗?
问题似乎与未指定内存容量有关,如果您按如下方式指定内存容量,
这里我指定内存容量为1MB大小
[[NSURLCache alloc] initWithMemoryCapacity:1*1024*1024 diskCapacity:sz diskPath:nil];
会用,我觉得好像内存容量是需要的,容量再小又不能为空。然后你将能够提取存储缓存如下,
NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request];
response = cachedResponse.response;
data = cachedResponse.data;
最后我重写了 NSURLCache 以实现我想要的:
- GET 请求(带有参数)被缓存到磁盘
- 当 "Cache-Control max-age" 值表示未过期时请求将缓存,并在过期后再次转到服务器,存储新响应并开始过期时间
- 如果离线,总是return来自缓存的响应(如果存在)
NTURLCache - overrides NSURLCache
我认真地认为这是一个在 iOS 8.1
中无法正常工作的问题
iOS 11.x
的问题仍然存在,尽管我有一个 iPad 迷你 运行 版本 iOS 9.3.5
,它具有完美的缓存。 NSURLCache/URLCache
肯定有问题
我正在尝试使用 NSURLCache 将一些 HTTP 请求缓存到磁盘。在使用 AFNetworking 进行了一些测试但没有工作之后,我使用 NSURLRequest 创建了一个简单的示例。
我像这样初始化 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 Header Cache-Control 比如:
响应['cache-control'] = 'max-age=36000, public'
我看到响应缓存在文件 Cache.db.
中后来,在下一次甚至同一次执行中,我使用以下代码尝试从缓存中获取响应:
NSCachedURLResponse *cachedResponse = [urlCache cachedResponseForRequest:request];
response = cachedResponse.response;
data = cachedResponse.data;
问题是当请求上有 GET 参数时,cachedResponse 总是 null 。如果请求是“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 参数时它不能正常工作有什么想法吗?
问题似乎与未指定内存容量有关,如果您按如下方式指定内存容量,
这里我指定内存容量为1MB大小
[[NSURLCache alloc] initWithMemoryCapacity:1*1024*1024 diskCapacity:sz diskPath:nil];
会用,我觉得好像内存容量是需要的,容量再小又不能为空。然后你将能够提取存储缓存如下,
NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request];
response = cachedResponse.response;
data = cachedResponse.data;
最后我重写了 NSURLCache 以实现我想要的:
- GET 请求(带有参数)被缓存到磁盘
- 当 "Cache-Control max-age" 值表示未过期时请求将缓存,并在过期后再次转到服务器,存储新响应并开始过期时间
- 如果离线,总是return来自缓存的响应(如果存在)
NTURLCache - overrides NSURLCache
我认真地认为这是一个在 iOS 8.1
中无法正常工作的问题iOS 11.x
的问题仍然存在,尽管我有一个 iPad 迷你 运行 版本 iOS 9.3.5
,它具有完美的缓存。 NSURLCache/URLCache