博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
接口请求的本地缓存策略
阅读量:6553 次
发布时间:2019-06-24

本文共 5041 字,大约阅读时间需要 16 分钟。

hot3.png

# 接口请求的本地缓存策略

 

本文是在 AFNetworking 的基础上,加入了本地缓存策略,并对请求错误,进行了定制,以统一前端对用户的错误提示。

 

## 缓存策略

 

包含3种策略,详见以下缓存策略的定义说明。

 

```

/**

 接口缓存策略

 */

typedef NS_ENUM(NSUInteger, TTVRequestCachePolicy) {

    //1、先查询本地缓存

    //2.1、有缓存则直接返回

    //2.2、无缓存则请求服务器后返回,并更新本地缓存

    TTVRequestCachePolicyNormal,

    

    //不使用缓存,直接请求服务器

    TTVRequestCachePolicyOnline,

    

    //1、先查询本地缓存。

    //2.1、有缓存则返回,然后请求服务器再次返回,并更新本地缓存。

    //2.2、无缓存则联网请求服务器返回最新数据,并更新本地缓存。

    TTVRequestCachePolicyHybrid,

};

```

 

### 策略对应的业务需求

 

##### TTVRequestCachePolicyNormal

只取本地缓存的数据返回。同时在后台请求最新的数据,并更新缓存。

 

对应的业务需求是,一些更新周期非常长的数据,可以使用此种策略。

 

##### TTVRequestCachePolicyOnline

只请求最新的网络数据。

 

对应一些不需要使用到本地缓存的业务需求。

 

##### TTVRequestCachePolicyHybrid

先返回本地缓存数据,再返回最新的网络数据。

 

因为App端有一种通用的需求,就是在没有网络或网络较差时,需要先展示本地缓存的数据,同时请求最新数据,请求成功后,将获取到的最新数据更新到UI上。

 

 

 

## 请求成功或失败的回调block

 

### 请求成功的处理

 

```

/**

 请求的成功回调

 

  responseObject  返回的正确数据

  isCache         是否缓存

 */

typedef void (^TTVRequestSuccessBlock)(id  _Nullable responseObject, BOOL isCache);

```

 

指定的返回的数据,以及 `isCache` 代表是否来自本地缓存

 

### 请求失败的处理

 

```

/**

 请求的失败回调

 

  errCode     错误码

  errMessage  错误消息

 */

typedef void (^TTVRequestFailureBlock)(NSInteger errCode, NSString *_Nullable errMessage);

```

 

请求失败的回调block,指定了错误码和错误提示语,在调用请求接口时,可直接使用并展示给用户。

 

在请求过程中,加入了网络错误的判断,直接返回指定的网络错误提示语,并中断请求。

 

 

## 有待优化

 

对于本地缓存策略,需要加入缓存有效期。

 

 

## 完整代码示例

 

```

/**

 GET或者POST请求

 

  isGetOrPost             YES:GET请求,NO:POST请求

 @param URLString               请求的URL

 @param parameters              请求参数

 @param cachePolicy             缓存策略

 @param cacheKey                缓存key,命名方式:模块名+id+userId

 @param downloadProgressBlock   请求成功下载加载进度回调Block

 @param successBlock            请求成功调用Block,Block中的responseObject参数

 @param failureBlock            请求失败调用Block

 @return

 */

+ (nonnull NSURLSessionDataTask *)request:(BOOL)isGetOrPost

                                      url:(nonnull NSString *)URLString

                               parameters:(nullable id)parameters

                              cachePolicy:(TTVRequestCachePolicy)cachePolicy

                                 cacheKey:(NSString *_Nullable)cacheKey

                                 progress:(void (^ _Nullable)(NSProgress * _Nonnull progress))downloadProgressBlock

                                  success:(TTVRequestSuccessBlock)successBlock

                                  failure:(TTVRequestFailureBlock)failureBlock

{

    TTVLogVerbose(@"GET Request with Cache>>>>>>>>>> [%@][%@]", URLString, parameters);

    AFHTTPSessionManager *manager = [TTVNetworkManager ttv_addHeaderForSignWithRequestURL:URLString mathod:isGetOrPost ? @"GET" : @"POST" parameters:parameters needToDecrypt:YES];

    

    __block YYCache *yyCache = [YYCache cacheWithName:@"TTVRequestCache"];

    

    //缓存key,加上版本号,用于升级接口后的数据更新

    __block NSString *cacheKeyFinal = [NSString stringWithFormat:@"%@+%@", cacheKey, [[self class] getServerAPIVesion:URLString]];

    

    //成功回调处理

    void (^doSuccessBlock)(id, BOOL) = ^(id responseObject, BOOL isCache) {

        

        TTVLogVerbose(@"GET Request with Cache Success<<<<<<<<<<[ %@ ]\n isCache:%@\n responseObject: %@ \n\n", URLString, @(isCache), responseObject);

        

        if (successBlock) {

            successBlock(responseObject, isCache);

            if (!isCache) {

                [self checkResponseObject:responseObject];

            }

        }

    };

    

    //失败回调处理

    void (^doFailureBlock)(NSError *, TTVRequestFailureBlock) = ^(NSError *error, TTVRequestFailureBlock failureBlock) {

        

        TTVLogWarn(@"GET Request with Cache Failure<<<<<<<<<<[ %@ ]\n%@\n\n", URLString, error);

        

        //返回具体的错误提示

        if (failureBlock) {

            TTVNetWorkError *netWorkError = [TTVNetWorkError ttv_errorWithError:error userInfo:error.userInfo];

            NSInteger errorCode = 0;

            if (error) {

                errorCode = [error.userInfo[@"body"][@"errorCode"] integerValue];

            }

            failureBlock(errorCode, netWorkError.ttv_tips);

        }

    };

    

    //请求

    void (^requestBlock)(BOOL) = ^(BOOL isGetOrPost)

    {

        /********************************

         无网络时,直接返回错误消息

         */

        AFNetworkReachabilityStatus status = [AFNetworkReachabilityManager sharedManager].networkReachabilityStatus;

        if (status == AFNetworkReachabilityStatusNotReachable) {

            if (failureBlock) {

                failureBlock(TTVRequestErrorCodeNoNetwork, TTVErrorMessageNoNetwork);

            }

            return;

        }

        

        /********************************

         网络正常时,继续请求

         */

        if (isGetOrPost) {

            [manager GET:URLString

              parameters:parameters

                progress:nil

                 success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject)

             {

                 doSuccessBlock(responseObject, NO);

                 [yyCache setObject:responseObject forKey:cacheKeyFinal];

             }

                 failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error)

             {

                 doFailureBlock(error, failureBlock);

             }];

        } else {

            [manager POST:URLString

               parameters:parameters

                 progress:nil

                  success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject)

             {

                 doSuccessBlock(responseObject, NO);

                 [yyCache setObject:responseObject forKey:cacheKeyFinal];

             }

                  failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error)

             {

                 doFailureBlock(error, failureBlock);

             }];

        }

    };

    

    /********************************

     处理数据,缓存逻辑

     */

    if (cachePolicy == TTVRequestCachePolicyNormal) {

        id cacheData = [yyCache objectForKey:cacheKeyFinal];

        if (cacheData) {

            //返回缓存

            doSuccessBlock(cacheData, YES);

        } else {

            //请求服务器

            requestBlock(isGetOrPost);

        }

    } else if (cachePolicy == TTVRequestCachePolicyOnline) {

        //请求服务器

        requestBlock(isGetOrPost);

    } else if (cachePolicy == TTVRequestCachePolicyHybrid) {

        //返回缓存

        id cacheData = [yyCache objectForKey:cacheKeyFinal];

        if (cacheData) {

            doSuccessBlock(cacheData, YES);

        }

        

        //请求服务器,再返回一次

        requestBlock(isGetOrPost);

    }

    

    //返回空

    return nil;

}

```

转载于:https://my.oschina.net/u/3729372/blog/1596608

你可能感兴趣的文章
为YUM设置代理的方法
查看>>
Java 编程的动态性 第1 部分: 类和类装入--转载
查看>>
再谈ABC
查看>>
【转】持久化消息队列之MEMCACHEQ
查看>>
java-Mail
查看>>
Dom4j学习笔记
查看>>
C语言 HTTP上传文件-利用libcurl库上传文件
查看>>
[MEAN Stack] First API -- 7. Using Route Files to Structure Server Side API
查看>>
调试逆向分为动态分析技术和静态分析技术(转)
查看>>
Android webview使用详解
查看>>
业务对象和BAPI
查看>>
程序源系统与当前系统不一致:Carry out repairs in non-original systems only if urgent
查看>>
微软职位内部推荐-Senior Software Engineer
查看>>
程序中的魔鬼数字
查看>>
SVN高速新手教程
查看>>
session cookie
查看>>
如何在Vblock里配置Boot from SAN
查看>>
ZBar之ZBarReaderViewController
查看>>
Nuget~管理自己的包包~丢了的包包快速恢复
查看>>
Hadoop单机模式安装-(3)安装和配置Hadoop
查看>>