请求缓存:
一. 每次请求都有根用户信息有关的固定参数,我们称之为commonArgument,如
SessionID,CityId,Lat,Lng,DeviceID,Version,IsInHouse,devType,OS,AppVer,AppBuild等,具体如何获得的,以后再说。
主要方式是,根据请求的url生成一个字符串作为Key,Value是请求回来的数据。
Key的组成:
1.baseUrl和requestUrl,baseUrl可以在AFHTTPRequestOperationManager中设置,获取。
2.请求方法类型,get,post,delete等。
3.请求参数
4.版本信息
最后要把生成的url用md5加密便于管理。
主要是请求参数的处理:去掉每次请求都会变的东西,要不每次请求都会当作新请求,失去缓存的意义。
[dic removeObjectsForKeys:@[@"nonce", @"sign", @"time", @"token", @"SessionID", @"Lat", @"Lng",@"latitude",@"longitude"]];
二.NWCacheArgument 类
此类是用来封装缓存的一些信息,它包含要缓存的请求key,是否忽略缓存,是否支持离线缓存,以及缓存的时间。
@protocol NWCacheArgumentProtocol <NSObject>
- (void)cacheResponseWithIgnoreCache:(BOOL)ignoreCache
supportOffLine:(BOOL)supportOffLine
cacheTimeInSeconds:(NSInteger)cacheTimeInSeconds;
@end
@interface NWCacheArgument : NSObject<NWCacheArgumentProtocol>
@property (nonatomic, strong, readonly) NSString *key;
/** 忽略缓存直接请求*/
@property (nonatomic, assign) BOOL ignoreCache;
/** 是否支持离线缓存,默认不支持*/
@property (nonatomic, assign) BOOL supportOffLine;
@property (nonatomic, assign) NSInteger cacheTimeInSeconds;
- (id)initWithKey:(NSString *)key;
@end
对于此类,我们可以这么理解,一个请求对应一个CacheArgument,我们可以在这个缓存配置类中设置默认的一些配置。如果我想修改这些配置,怎么办呢?这就是上述这个代理的协议的作用,缓存配置类实现了自己的协议,那么我们就可以在调用请求的时候,传入一个Block,然后我们把新创建的缓存配置类作为此Block的参数,它当然就实现了这个协议,然后在block的回调内调用代理类方法。
根据路径判断缓存文件是否存在,如果不存在则表明没有缓存过,发送请求,如果存在,根据缓存文件最近一次的修改时间判断是否过期,如果过期则发送请求,如果没有,则读取NWCache,然后反解档并且封装NWResult
关于NWCache和NWResult以后再讨论。
三.发起请求
HttpMethodGet,
HttpMethodPost,
HttpMethodDelete,
HttpMethodunPostAndDelete
对于Post,经常会处理上传图片,NSData,NSURL 格式的参数,我们可以对这些做单独处理,这样有助于统一,不用每次请求都做一次处理。
如图片,我们可以对UIImage做统一压缩处理然后再上传。
另外,我们可以对 音频 视频 压缩包 图片 等NSURL指向的文件做处理,AFN最终都会把请求数据封装到
formData中,利用如下方式。
opreration = [selfPOST:URLStringparameters:newParametersconstructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formDataDic enumerateKeysAndObjectsUsingBlock:^(id key,id obj,BOOL *stop){
//TODO:在此只是单独处理POST过程中音频输入
if ([keyisEqualToString:@"msg"] && [objisKindOfClass:[NSURLclass]]) {
NSURL *url = obj;
NSString *fileName = [[urlpathComponents]lastObject];;
NSError *error =nil;
[formData appendPartWithFileURL:objname:keyfileName:fileNamemimeType:@"audio/mpeg"error:&error];
//压缩包
}elseif ([keyisEqualToString:@"Bbox"] && [objisKindOfClass:[NSURLclass]]) {
NSURL *url = obj;
NSString *fileName = [[urlpathComponents]lastObject];;
[formData appendPartWithFileData:[NSDatadataWithContentsOfFile:[urlpath]]
name:key
fileName:fileName
mimeType:@"application/zip"];
}else{//图片
NSString *fileName =[NSStringstringWithFormat:@"%@.jpg", key];
[formData appendPartWithFileData:objname:keyfileName:fileNamemimeType:@"image/jpeg"];
}
四:请求成功后
//请求成功的处理,主要是把请求获得的数据封装到NWResult中,和归档缓存请求数据。
- (void)operationSuccessWithAFHTTPRequestOperation:(AFHTTPRequestOperation *)operation responseObject:(id)responseObject
operationCompleteBlock:(OperationCompleteBlock)completeBlock
cacheArgument:(NWCacheArgument *)cacheArgument{
NSDictionary *jsonDic =nil;
if ([responseObjectisKindOfClass:[NSDictionaryclass]]) {
jsonDic = responseObject;
}else{
//TODO:由于历史遗留问题,这里全部使用GBK重新解析一下数据
NSStringEncoding enc =CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);
NSString *responseString = [[NSStringalloc]initWithData:operation.responseDataencoding:enc];
responseString = [responseString stringByReplacingOccurrencesOfString:@"\n"withString:@""];
responseString = [responseString stringByReplacingOccurrencesOfString:@"\r"withString:@""];
jsonDic = [responseString objectFromJSONString];
}
NWResult *result = [NWResultresultWithAttributes:jsonDic];
if (completeBlock) {
completeBlock(operation, result);
}
if (result.success) {
[selfsaveJsonResponseToCacheFile:jsonDicwithCacheArgument:cacheArgument];
}
}
五。请求失败后
//请求失败的处理,从内存中直接读取(不用判断时间过期情况,如果内存中没有,从缓存文件中解档),如果还是没有读取数据,判断网络情况
self.reachabilityManager.reachable,如果网络良好,服务端会返回相应错误,当然如果网络不好,自己组装网络无法连接信息。
- (void)operationFailureWithAFHTTPRequestOperation:(AFHTTPRequestOperation *)operation
error:(NSError *)error
operationCompleteBlock:(OperationCompleteBlock)completeBlock
cacheArgument:(NWCacheArgument *)cacheArgument{
NWResult *result =nil;
NSData *data = [[NWCachesharedInstance]readForKey:cacheArgument.key];
NSDictionary *cacheObject =nil;
if (data) {
cacheObject = [NSKeyedUnarchiverunarchiveObjectWithData:data];
}
if (isDictWithCountMoreThan0(cacheObject)) {
result = [NWResultresultWithAttributes:cacheObject];
[result setDataFromCache:YES];
[result setFailureRequest:YES];
}else{
if (!self.reachabilityManager.reachable) {
NSDictionary *userInfo =@{NSLocalizedDescriptionKey:@"当前网络无法连接,请稍候重试!"};
error = [NSErrorerrorWithDomain:CustomErrorDomaincode:MWHttpRequestErrorFailedConnectuserInfo:userInfo];
}
result = [NWResultresultWithNSError:error];
[result setFailureRequest:YES];
}
if (completeBlock) {
completeBlock(operation, result);
}
}
- (NSString *)applicationCachesDirectory;
//TODO: 返回是否当前缓存需要更新
- (BOOL)isCacheVersionExpiredForKey:(NSString *)key toCacheTimeInSeconds:(int)seconds;
- (NSData*)readForKey:(NSString*)key;
- (BOOL)write:(NSData*)data forKey:(NSString*)key;
//只读取用户信息
- (id)userReadForKey:(NSString*)key;
- (BOOL)writeUserModel:(id)user forKey:(NSString *)key;