前言叨逼叨
- HS的1.5版本多灾多难,被SBPM蹂躏一番之后还是如期上线了,最近先下重新看以前网络的基础资料,进行知识储备,现在总结一些零落的知识点。
- 书归正传,以前常听说get 请求是可以缓存的,但是一直不知道具体含义,今天具体讲解一下get的缓存,以及具体的代码实现
苹果提供缓存策略
首先我们了解一下苹果提供了那些缓存策略
NSURLRequestUseProtocolCachePolicy = 0, 默认的缓存策略, 如果缓存不存在,直接从服务端获取。如果缓存存在,会根据response中的Cache-Control字段判断下一步操作,如: Cache-Control字段为must-revalidata, 则询问服务端该数据是否有更新,无更新的话直接返回给用户缓存数据,若已更新,则请求服务端.
NSURLRequestReloadIgnoringLocalCacheData = 1, 忽略本地缓存数据,直接请求服务端.
NSURLRequestIgnoringLocalAndRemoteCacheData = 4, 忽略本地缓存,代理服务器以及其他中介,直接请求源服务端.
NSURLRequestReloadIgnoringCacheData 略本地和远程的缓存数据,直接从原始地址下载,从API中可以看出是和NSURLRequestReloadIgnoringCacheData一样的。
NSURLRequestReturnCacheDataElseLoad = 2, 有缓存就使用,不管其有效性(即忽略Cache-Control字段), 无则请求服务端.
NSURLRequestReturnCacheDataDontLoad = 3, 死活加载本地缓存. 没有就失败. (确定当前无网络时使用)
NSURLRequestReloadRevalidatingCacheData = 5, 缓存数据必须得得到服务端确认有效才使用(貌似是NSURLRequestUseProtocolCachePolicy中的一种情况)
具体讲解
- 在web开发或者客户端开发大多数网络请求中(下载之类的除外),缓存一般都是不利的,使我们对数据的准确性的判断造成问题,故,我们在基本的网络访问的时候,通常忽略本地缓存,下面的代码演练中我们也是采取这样的原则,将缓存策略定为1
NSMutableURLRequest *requestM = [NSMutableURLRequest requestWithURL:self.url cachePolicy:1 timeoutInterval:10];
在请求头中,有一个键值是 If-None-Match
,响应头里有一个键值是Etag
,所以基本思路时,在一次请求结束以后,我们将响应头中的Etag
记录,在下次发起请求的时候,将其设置给请求头中的If-None-Match
,即将本地的缓存与服务器返回的内容进行对比,如果response
的statusCode
为304,表明服务器和本地缓存一直,没发生变化
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSURL *url = [NSURL URLWithString:@"http://localhost/itcast/images/head1.png"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:1 timeoutInterval:10.0];
if (self.etag.length > 0) {
NSLog(@"%@", self.etag);
[request setValue:self.etag forHTTPHeaderField:@"If-None-Match"];
}
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
NSLog(@"%@", httpResponse);
// 判断服务器返回的状态码,是否是 304
if (httpResponse.statusCode == 304) {
NSLog(@"加载缓存数据");
NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request];
data = cachedResponse.data;
}
self.etag = httpResponse.allHeaderFields[@"Etag"];
self.iconView.image = [UIImage imageWithData:data];
}];
}
全局缓存区设置
NSURLCache *urlCache = [[NSURLCache alloc] initWithMemoryCapacity:4 * 1024 * 1024 diskCapacity:20 * 1024 * 1024 diskPath:nil];
[NSURLCache setSharedURLCache:urlCache];
简单的小结一下
- 请求的缓存策略使用 NSURLRequestReloadIgnoringCacheData,忽略本地缓存
- 服务器响应结束后,要记录 Etag,服务器内容和本地缓存对比是否变化的重要依据
- 在发送请求时,设置 If-None-Match,并且传入 Etag
- 连接结束后,要判断响应头的状态码,如果是 304,说明本地缓存内容没有发生变化
后续
- GET 缓存的数据会保存在 Cache 目录中 \bundleId 下 Cache.db 中
- cfurl_cache_receiver_data,缓存所有的请求数据
- cfurl_cache_response,缓存所有的响应
可以用过SQLite去查看,后续文字可能会更新