NSURLCach工作原理
1. 请求前的配置,包括请求头,响应头,超时时间以及缓存策略 ( 后面会说到有关缓存策略 ) 。 2. 真正去服务器请求前,判断缓存策略,调用 cachedResponseForRequest: ( NSURLRequest * ) request 方法试着取缓存或者直接请求网络。 3. 如果缓存策略允许取缓存,并且取到了缓存,请求成功并且返回缓存数据。 4. 如果缓存策略允许取缓存,并且没有取到缓存,再次判断缓存策略,如果缓存策略允许联网,则联网请求,否则,请求失败。 5. 上述 2,3 任何一种请求成功的话,判断缓存策略和服务器返回的响应头。如果允许存储,则调用 storeCachedResponse: ( NSCachedURLResponse * ) cachedResponse forRequest: ( NSURLRequest * ) request 将返回的数据存储到内存以及硬盘,否则,直接返回请求成功。
NSURLCach的缓存策略(缓存和请求的自由组合)
如果使用了默认缓存策略,也就是上面表格中第一个,需要从返回的 response 的 header 中获取相应的字段来指导缓存该如何进行。 1.Cache-Control 字段:常用的有 no-cache,no-store,和 max-age。其中 no-cache 代表不能使用这个缓存,no-store 代表不存储这个数据,max-age 代表缓存的有效期 ( 单位为秒 ) 。 2.Expires 字段:缓存过期时间,后面跟一个日期,此日期之前都可以直接使用本缓存。如果 Expires 与 Cache-Control 同时存在,则 Cache-Control 优先。 3.Last-Modified 和 If-Modified-Since 字段:如果 response 中有 Last-Modified,则在下次请求时,给 request 的 header 设置 If-Modified-Since 为 Last-Modified 的值,服务器校验数据是否有变化,如果有变化,返回新数据,否则,返回 304 状态码,可以使用此缓存。 4.ETag 和 If-None-Match 字段:如果 response 中有 ETag,则在下次请求时,给 request 的 header 设置 If-None-Match 为 ETag 的值,服务器校验数据是否有变化,如果有变化,返回新数据,否则,返回 304 状态码,可以使用此缓存。
使用的步骤
1.配置自定义缓存类
NSUInteger memoryCapacity = 20*1024*1024;
NSUInteger diskCapacity = 50*1024*1024;
WXYURLCache *customURLCache = [[WXYURLCache alloc] initWithMemoryCapacity:memoryCapacity diskCapacity:diskCapacity diskPath:[WXYURLCache customCachePath]]; [NSURLCache setSharedURLCache:customURLCache];
设置缓存的类型(内存和硬盘),缓存的大小,缓存的位置,缓存的策略
2.设置请求
+ (void)requestWithSuccess:(SuccessBlock)success failure:(failureBlock)failure{ AFHTTPSessionManager *sessionManager = [AFHTTPSessionManager manager]; //配置请求头 sessionManager.requestSerializer = [AFHTTPRequestSerializer serializer]; sessionManager.requestSerializer.cachePolicy = [self getCachePolicy];//缓存策略 //配置响应头 sessionManager.responseSerializer = [AFJSONResponseSerializer serializer]; [sessionManager GET:customURLString parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { NSLog(@" 请求成功: URL:%@ response:%@ ", task.currentRequest.URL.absoluteString, responseObject); success(responseObject); } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { NSLog(@" 请求失败: URL:%@ error:%@ ", task.currentRequest.URL.absoluteString, [error.userInfo objectForKey:@"NSLocalizedDescription"]); failure(error); }]; }
3.重写缓存的方法(取缓存和存缓存)
- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request{ NSCachedURLResponse *cachedURLResponse = [super cachedResponseForRequest:request]; id cacheData = nil; if (!cachedURLResponse.data) { cacheData = @"取到的缓存为空"; } else{ cacheData = [NSJSONSerialization JSONObjectWithData:cachedURLResponse.data options:NSJSONReadingMutableContainers error:nil]; } NSLog(@" 取缓存: URL:%@ response:%@ ", request.URL.absoluteString, cacheData); return cachedURLResponse; }
- (void)storeCachedResponse:(NSCachedURLResponse *)cachedResponse forRequest:(NSURLRequest *)request{ id cacheData = [NSJSONSerialization JSONObjectWithData:cachedResponse.data options:NSJSONReadingMutableContainers error:nil]; NSLog(@" 存缓存: URL:%@ response:%@ ", request.URL.absoluteString, cacheData); [super storeCachedResponse:cachedResponse forRequest:request]; }
伪造响应
NSLog(@"%@",[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]);
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://172.16.25.44/test1.php"] cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:3]; NSURLCache * cache = [NSURLCache sharedURLCache]; NSData *contentData = [@"123" dataUsingEncoding:NSUTF8StringEncoding]; NSURLResponse *response = [[NSURLResponse alloc] initWithURL:[NSURL URLWithString:@"http://172.16.25.44/test1.php"] MIMEType:@"text/html" expectedContentLength:1000 textEncodingName:@"UTF-8"]; NSCachedURLResponse *cacheRespone = [[NSCachedURLResponse alloc] initWithResponse:response data:contentData];
[cache storeCachedResponse:cacheRespone forRequest:request]; connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection start];
修改响应内容
想要修改内容,要实现NSConnectionDataDelegate方法的willCachResponse方法
-(NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse { NSMutableData *mutableData = [[cachedResponse data] mutableCopy]; //添加数据 NSCachedURLResponse *response = [[NSCachedURLResponse alloc] initWithResponse:cachedResponse.response data:mutableData]; return response; }