美文网首页收藏家-源码阅读iOS Swift && Objective-CiOS Developer
YTKNetwork 源码阅读(二)-一次POST请求的完整历程

YTKNetwork 源码阅读(二)-一次POST请求的完整历程

作者: RubyAhooo | 来源:发表于2017-03-11 20:07 被阅读2246次

写在前面:

  1. 这篇文写了什么?
    用YTKNetwork走一次网络请求的完整历程。

  2. 我能看到哪些内容?
    以下是YTKNetwork官方文档的原话,说的是相比 AFNetworking,YTKNetwork 提供了以下更高级的功能,其中,后面打对号的部分是在这个历程中能看到的风景。

    • 支持按时间缓存网络请求内容 ✅
    • 支持按版本号缓存网络请求内容 ✅
    • 支持统一设置服务器和 CDN 的地址 ✅
    • 支持检查返回 JSON 内容的合法性 ✅
    • 支持文件的断点续传
    • 支持 block 和 delegate 两种模式的回调方式 ✅
    • 支持批量的网络请求发送,并统一设置它们的回调(实现在 YTKBatchRequest 类中)
    • 支持方便地设置有相互依赖的网络请求的发送,例如:发送请求 A,根据请求 A 的结果,选择性的发送请求 B 和 C,再根据 B 和 C 的结果,选择性的发送请求 D。(实现在 YTKChainRequest 类中)
    • 支持网络请求 URL 的 filter,可以统一为网络请求加上一些参数,或者修改一些路径。 ✅
    • 定义了一套插件机制,可以很方便地为 YTKNetwork 增加功能。猿题库官方现在提供了一个插件,可以在某些网络请求发起时,在界面上显示“正在加载”的 HUD。

旅程前的准备:(这一部分是YTKNetwork的基础用法,可以略过不看)

  1. 设置baseUrl
    //支持统一设置服务器和 CDN 的地址 ✅
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    YTKNetworkConfig *config = [YTKNetworkConfig sharedConfig];
    config.baseUrl = @"http://yuantiku.com";
    }

  2. 创建请求类

     // UserInfoRequest.m
     @interface UserInfoRequest () {
         NSString *_uid;
     }
     @end
    
     @implementation UserInfoRequest
    
     - (instancetype)initWithUid:(NSString *)uid {
         self = [super init];
         if (self) {
             _uid = uid;
         }
         return self;
     }
    
     - (NSString *)requestUrl {
         return @"/OwoccAppAPI/api/user";
     }
    
     - (YTKRequestMethod)requestMethod {
         return YTKRequestMethodPost;
     }
    
     - (id)requestArgument {
         return @{
                 @"uid": _uid,
                 };
     }
    

启程

  1. 开始一个新请求

     NSString *uid = @"1002";
     //1. 创建一个请求实例,uid是参数。这个请求是post。
     UserInfoRequest *userInfoReq = [[UserInfoRequest alloc] initWithUid:uid];
     //2. 便利请求方法,选择了block回调的方式。点进这个方法,去看看它的实现。
     [userInfoReq startWithCompletionBlockWithSuccess:^(YTKBaseRequest *request) {
         NSLog(@"请求成功,返回数据:%@",request.responseString);
     } failure:^(YTKBaseRequest *request) {
         NSLog(@"请求失败");
     }];
    
  2. 请求便利方法

     - (void)startWithCompletionBlockWithSuccess:(void (^)(YTKBaseRequest *request))success
                                         failure:(void (^)(YTKBaseRequest *request))failure {
         //1. 设置好成功和失败的回调。请看下                                   
         [self setCompletionBlockWithSuccess:success failure:failure];
         //2. 开始
         [self start];
     }
    
     - (void)setCompletionBlockWithSuccess:(void (^)(YTKBaseRequest *request))success
                                 failure:(void (^)(YTKBaseRequest *request))failure {
         self.successCompletionBlock = success;
         self.failureCompletionBlock = failure;
     }
    
  3. 开始请求,首先看能不能从缓存拿数据

     - (void)start {
         //1. 如果忽略缓存,直接开始请求。如果不忽略,往下 走
         if (self.ignoreCache) {
             [super start];
             return;
         }
    
         //2. 支持按时间缓存网络请求内容 ✅。如果没有设置cacheTimeInSeconds,直接开始请求。如果设置了,往下 走
         if ([self cacheTimeInSeconds] < 0) {
             [super start];
             return;
         }
    
         //3. 支持按版本号缓存网络请求内容✅。
         long long cacheVersionFileContent = [self cacheVersionFileContent]; //已经缓存内容的版本号
         //如果cacheVersionFileContent和这个请求的版本号不同的话,直接开始请求。如果相同,往下 走
         if (cacheVersionFileContent != [self cacheVersion]) {
             [super start];
             return;
         }
    
         //4. 查看缓存是否存在。如果不存在,直接开始请求。如果存在,往下 走。缓存在沙盒中的路径是: /Library/LazyRequestCache/POST+完整链接地址+参数+应用版本号+敏感内容
         NSString *path = [self cacheFilePath];
         NSFileManager *fileManager = [NSFileManager defaultManager];
         if (![fileManager fileExistsAtPath:path isDirectory:nil]) {
             [super start];
             return;
         }
    
         //5. 检查缓存文件最后一次修改时间到现在的间隔。如果间隔大于我们设置的cacheTimeInSeconds直接开始请求。如果小于,往下 走
         int seconds = [self cacheFileDuration:path];
         if (seconds < 0 || seconds > [self cacheTimeInSeconds]) {
             [super start];
             return;
         }
    
         //6. 从缓存中拿数据。如果为nil,直接开始请求。如果不为nil,往下 走
         _cacheJson = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
         if (_cacheJson == nil) {
             [super start];
             return;
         }
    
         //7. 如果走到这里了,说明没有走接口,直接从缓存拿的数据。
          _dataFromCache = YES;//第一步
         [self requestCompleteFilter];//第二步
         //第三步:走请求完成的回调。支持 block 和 delegate 两种模式的回调方式 ✅
         YTKRequest *strongSelf = self;
         [strongSelf.delegate requestFinished:strongSelf];
         if (strongSelf.successCompletionBlock) {
             strongSelf.successCompletionBlock(strongSelf);
         }
         [strongSelf clearCompletionBlock];//把成功和失败的block置为nil
     }
    
  4. 请求真正开始(没能从缓存拿数据)

     /// append self to request queue
     - (void)start {
         [self toggleAccessoriesWillStartCallBack];//不用看
         //command 设计模式:把request传给接收器(这里就是YTKNetworkAgent)
         [[YTKNetworkAgent sharedInstance] addRequest:self];
     }
    
  5. YTKNetworkAgent的addRequest:方法

     - (void)addRequest:(YTKBaseRequest *)request {
         //1. 获取请求方法,这里是POST
         YTKRequestMethod method = [request requestMethod];
         //2. 组合完整链接地址: baseUrl + requestUrl
         //支持网络请求 URL 的 filter,可以统一为网络请求加上一些参数,或者修改一些路径。✅
         NSString *url = [self buildRequestUrl:request];
         //3. 请求参数
         id param = request.requestArgument;
         //4.
         AFConstructingBlock constructingBlock = [request constructingBodyBlock];
         //5. 请求序列化类型
         if (request.requestSerializerType == YTKRequestSerializerTypeHTTP) {
             _manager.requestSerializer = [AFHTTPRequestSerializer serializer];
         } else if (request.requestSerializerType == YTKRequestSerializerTypeJSON) {
             _manager.requestSerializer = [AFJSONRequestSerializer serializer];
         }
         //6. 请求超时时间。可以自定义,默认60s
         _manager.requestSerializer.timeoutInterval = [request requestTimeoutInterval];
    
         //7. 如果需要的话,设置访问服务器的username和password
         NSArray *authorizationHeaderFieldArray = [request requestAuthorizationHeaderFieldArray];
         if (authorizationHeaderFieldArray != nil) {
             [_manager.requestSerializer setAuthorizationHeaderFieldWithUsername:(NSString *)authorizationHeaderFieldArray.firstObject
                                                                     password:(NSString *)authorizationHeaderFieldArray.lastObject];
         }
         
         //8. 如果需要的话,配置一些请求头的信息
         NSDictionary *headerFieldValueDictionary = [request requestHeaderFieldValueDictionary];
         if (headerFieldValueDictionary != nil) {
             for (id httpHeaderField in headerFieldValueDictionary.allKeys) {
                 id value = headerFieldValueDictionary[httpHeaderField];
                 if ([httpHeaderField isKindOfClass:[NSString class]] && [value isKindOfClass:[NSString class]]) {
                     [_manager.requestSerializer setValue:(NSString *)value forHTTPHeaderField:(NSString *)httpHeaderField];
                 } else {
                     YTKLog(@"Error, class of key/value in headerFieldValueDictionary should be NSString.");
                 }
             }
         }
    
         //9. 自定义url。
         NSURLRequest *customUrlRequest= [request buildCustomUrlRequest];
         if (customUrlRequest) {
             //注意: 如果自定义了url,会忽略请求类的requestUrl, requestArgument, requestMethod, requestSerializerType
             AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:customUrlRequest];
             [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
                 [self handleRequestResult:operation];
             } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
                 [self handleRequestResult:operation];
             }];
             request.requestOperation = operation;
             operation.responseSerializer = _manager.responseSerializer;
             [_manager.operationQueue addOperation:operation];
         } else {
             //GET方法,我们这里的示例是POST,看下
             if (method == YTKRequestMethodGet) {
                 if (request.resumableDownloadPath) {
                     // add parameters to URL;
                     NSString *filteredUrl = [YTKNetworkPrivate urlStringWithOriginUrlString:url appendParameters:param];
    
                     NSURLRequest *requestUrl = [NSURLRequest requestWithURL:[NSURL URLWithString:filteredUrl]];
                     AFDownloadRequestOperation *operation = [[AFDownloadRequestOperation alloc] initWithRequest:requestUrl targetPath:request.resumableDownloadPath shouldResume:YES];
                     [operation setProgressiveDownloadProgressBlock:request.resumableDownloadProgressBlock];
                     [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
                         [self handleRequestResult:operation];
                     }                                failure:^(AFHTTPRequestOperation *operation, NSError *error) {
                         [self handleRequestResult:operation];
                     }];
                     request.requestOperation = operation;
                     [_manager.operationQueue addOperation:operation];
                 } else {
                     request.requestOperation = [_manager GET:url parameters:param success:^(AFHTTPRequestOperation *operation, id responseObject) {
                         [self handleRequestResult:operation];
                     }                                failure:^(AFHTTPRequestOperation *operation, NSError *error) {
                         [self handleRequestResult:operation];
                     }];
                 }
             } else if (method == YTKRequestMethodPost) {
                 //10. 开始请求,用的是AFNetworking
                 if (constructingBlock != nil) {
                     request.requestOperation = [_manager POST:url parameters:param constructingBodyWithBlock:constructingBlock
                                                     success:^(AFHTTPRequestOperation *operation, id responseObject) {
                                                         [self handleRequestResult:operation];
                                                     } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
                                 [self handleRequestResult:operation];
                             }];
                 } else {
                     request.requestOperation = [_manager POST:url parameters:param success:^(AFHTTPRequestOperation *operation, id responseObject) {
                         [self handleRequestResult:operation];
                     }                                 failure:^(AFHTTPRequestOperation *operation, NSError *error) {
                         //12. 请求完成,处理请求的结果.(11请看下面)
                         [self handleRequestResult:operation];
                     }];
                 }
             } else if (method == YTKRequestMethodHead) {
                 request.requestOperation = [_manager HEAD:url parameters:param success:^(AFHTTPRequestOperation *operation) {
                     [self handleRequestResult:operation];
                 }                                 failure:^(AFHTTPRequestOperation *operation, NSError *error) {
                     [self handleRequestResult:operation];
                 }];
             } else if (method == YTKRequestMethodPut) {
                 request.requestOperation = [_manager PUT:url parameters:param success:^(AFHTTPRequestOperation *operation, id responseObject) {
                     [self handleRequestResult:operation];
                 }                                failure:^(AFHTTPRequestOperation *operation, NSError *error) {
                     [self handleRequestResult:operation];
                 }];
             } else if (method == YTKRequestMethodDelete) {
                 request.requestOperation = [_manager DELETE:url parameters:param success:^(AFHTTPRequestOperation *operation, id responseObject) {
                     [self handleRequestResult:operation];
                 }                                   failure:^(AFHTTPRequestOperation *operation, NSError *error) {
                     [self handleRequestResult:operation];
                 }];
             } else if (method == YTKRequestMethodPatch) {
                 request.requestOperation = [_manager PATCH:url parameters:param success:^(AFHTTPRequestOperation *operation, id responseObject) {
                     [self handleRequestResult:operation];
                 } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
                     [self handleRequestResult:operation];
                 }];
             } else {
                 YTKLog(@"Error, unsupport method type");
                 return;
             }
         }
    
         YTKLog(@"Add request: %@", NSStringFromClass([request class]));
         //11. 把request存到_requestsRecord里面
         [self addOperation:request];
     }
    
  6. 处理请求的下来的数据handleRequestResult:

     - (void)handleRequestResult:(AFHTTPRequestOperation *)operation {
         NSString *key = [self requestHashKey:operation];
         //1. 把request从_requestsRecord拿出来
         YTKBaseRequest *request = _requestsRecord[key];
         YTKLog(@"Finished Request: %@", NSStringFromClass([request class]));
         //2. 如果request存在,接着往下走
         if (request) {
             // 支持检查返回 JSON 内容的合法性 ✅
             BOOL succeed = [self checkResult:request];
             if (succeed) {
                 //成功,走成功的回调
                 [request toggleAccessoriesWillStopCallBack];
                 [request requestCompleteFilter];
                 if (request.delegate != nil) {
                     [request.delegate requestFinished:request];
                 }
                 if (request.successCompletionBlock) {
                     request.successCompletionBlock(request);
                 }
                 [request toggleAccessoriesDidStopCallBack];
             } else {
                 //失败,走失败的回调
                 YTKLog(@"Request %@ failed, status code = %ld",
                         NSStringFromClass([request class]), (long)request.responseStatusCode);
                 [request toggleAccessoriesWillStopCallBack];
                 [request requestFailedFilter];
                 if (request.delegate != nil) {
                     [request.delegate requestFailed:request];
                 }
                 if (request.failureCompletionBlock) {
                     request.failureCompletionBlock(request);
                 }
                 [request toggleAccessoriesDidStopCallBack];
             }
         }
         //3. 把request从requestRecord移除出去
         [self removeOperation:operation];
         //4. 把成功和失败的block回调置为nil
         [request clearCompletionBlock];
     }
    

YTKNetwork 源码阅读(一)-整体框架

相关文章

网友评论

  • 王_a5ee:报错 NSString *filteredUrl = [YTKNetworkPrivate urlStringWithOriginUrlString:url appendParameters:param];,这里YTKNetworkPrivate无法调用
    urlStringWithOriginUrlString

本文标题:YTKNetwork 源码阅读(二)-一次POST请求的完整历程

本文链接:https://www.haomeiwen.com/subject/zldzgttx.html