Get请求缓存
iOS 5.0开始,支持磁盘缓存,但仅支持 HTTP
iOS 6.0开始,支持 HTTPS 缓存
// 设置网络缓存 - 4M 的内存缓存 20M 的磁盘缓存,使用默认的缓存路径 Caches/bundleId
NSURLCache *cache = [[NSURLCache alloc] initWithMemoryCapacity:4 * 1024 * 1024 diskCapacity:20 * 1024 * 1024 diskPath:nil];
// 设置全局缓存
[NSURLCache setSharedURLCache:cache];
上面的两句基本能解决所有的Get请求缓存,而我在自己的某个项目中,清一色的Post请求😂,这TM就尴尬了
今个看到一篇文章,说的是缓存问题,一想到自己做的缓存,存在问题,问题很大。由于我司对于app这一块,貌似也不是很关注,我也不打算改动了,等真正提BUG再改
逻辑漏洞
1.没有想到缓存过期问题
2.撤销缓存问题,现在是一把加载,这个要改改
首先要知道,POST请求不能被缓存,只有 GET 请求能被缓存。因为从数学的角度来讲,GET 的结果是幂等的,就好像字典里的 key 与 value 就是幂等的,而 POST 不 幂等。缓存的思路就是将查询的参数组成的值作为 key ,对应结果作为value。从这个意义上说,一个文件的资源链接,也叫 GET 请求,下文也会这样看待。
- 现在我的做法是,让Post也形成Key - value这种,用YYCache缓存
NSString * urlStr = [NSString stringWithFormat:@"%@%@",baseUrl,sonURl];
//处理中文和空格问题
urlStr = [urlStr stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
//拼接
NSString * cacheUrl = [self creatUniqueKeyForMD5:urlStr WithDict:paramterDictionary];
//对应的唯一的Key出来了
NSString * cacheKey = [SystemUtils md5:cacheUrl];
/**
* 创建一个key
*
* @param urlStr 网址
* @param parameters 参数
*
* @return 网址+参数按照一定规律来形成一个key,从而做缓存的MD5转一下,形成特定字符串key
*/
-(NSString *)creatUniqueKeyForMD5:(NSString *)urlStr WithDict:(NSDictionary *)parameters
{
if (!parameters) {
return urlStr;
}
/**
* 1.取出来所有Key
* 2.排序
*
*
*
*/
// NSMutableArray * lastArray = [NSMutableArray array];
NSArray * array = [parameters allKeys];
NSArray * sortArray = [array sortedArrayUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) {
return obj1>obj2;
}];
__block NSString * lastString = urlStr;
[sortArray enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
lastString = [NSString stringWithFormat:@"%@_%@_%@_",lastString,obj,[parameters objectForKey:obj]];
}];
NSLog(@"%@",lastString);
return lastString;
}
YYcache使用
如果有缓存,并且断网(我们的需求,大家也可以直接加载,等刷新数据再刷新)
//设置YYCache属性
YYCache *cache = [[YYCache alloc] initWithName:UserYYKitCache];
cache.memoryCache.shouldRemoveAllObjectsOnMemoryWarning = YES;
cache.memoryCache.shouldRemoveAllObjectsWhenEnteringBackground = YES;
id cacheData;
BadNetWork * badWork = [BadNetWork sharedInstance];
if (isCache) {
//根据网址从Cache中取数据
cacheData = [cache objectForKey:cacheKey];
if (cacheData != 0 &&badWork.isConnectNetWork == NO) {
//将数据统一处理 //如果没有网络并且存在缓存,则加载缓存
[self returnDataWithRequestData:cacheData Success:^(NSDictionary *requestDic, NSString *msg) {
YYLog(@"缓存数据\n\n %@ \n\n",requestDic);
successed(requestDic);
} failure:^(NSString *errorInfo) {
YYLog(@"缓存失败");
}];
}
}
问题来了》》》缓存失效了怎么办?
完全没考虑好缓存过期问题?等我研究好再来补充。。。待续
仔细看完文章后,来了解两个概念
1.Last-Modified
在浏览器第一次请求某一个URL时,服务器端的返回状态会是200,内容是客户端请求的资源,同时有一个Last-Modified的属性标记此文件在服务器端最后被修改的时间。
Last-Modified格式类似这样:
Last-Modified : Fri , 12 May 2006 18:53:33 GMT
客户端第二次请求此URL时,根据HTTP协议的规定,浏览器会向服务器传送If-Modified-Since报头,询问该时间之后文件是否有被修改过:
If-Modified-Since : Fri , 12 May 2006 18:53:33 GMT
如果服务器端的资源没有变化,则自动返回 HTTP 304(Not Changed.)状态码,内容为空,这样就节省了传输数据量。当服务器端代码发生改变或者重启服务器时,则重新发出资源,返回和第一次请求时类似。从而保证不向客户端重复发出资源,也保证当服务器有变化时,客户端能够得到最新的资源。
请求头 | 响应头 |
---|---|
Last-Modified | If-Modified-Since |
根据实际情况,让你们后台返回这些参数,然后判断即可,如果修改了,这返回HTTP304(Not Changed.)状态码,内容为空,这样就节省了传输数据量。
1.发送请求带上
[request setValue:Modified_value forHTTPHeaderField:@"If-Modified-Since"];
2.收到状态码
3.存储下value
实际上根据自己的来存下
AFN的response在:
YYLog(@" NSURLSessionDataTask:%@",task.response);
task.response找到Last-Modified用你的方式存储,下次请求的时候,Modified_value的值就是现在你存的
2.ETag(类似我们控制app登录的token,唯一性)
HTTP协议规格说明定义ETag为“被请求变量的实体值”。另一种说法是,ETag是一个可以与Web资源关联的记号(token)。典型的Web资源可以一个Web页,但也可能是JSON或XML文档。服务器单独负责判断记号是什么及其含义,并在HTTP响应头中将其传送到客户端,以下是服务器端返回的格式:ETag:"50b1c1d4f775c61:df3"客户端的查询更新格式是这样的:If-None-Match : W / "50b1c1d4f775c61:df3"如果ETag没改变,则返回状态304然后不返回,这也和Last-Modified一样。测试Etag主要在断点下载时比较有用。
思路参考Last-Modified,其中的区别,你可以参考文章
链接
本文大量参考这篇文章,谢谢@ChenYilong
概念性解释来源于😂百度百科😂