关于AFNetWorking3.0在failure回调时获取响应体信息

关键词:AFNetWorking3.0 failure回调 响应体

情景:

最近在开发中由于后台接口进行了重构,新版的接口执行restful api标准(反正后台是这么说的).于是作为苦逼前端的我们也跟着进行了接口联调更新.在调整是发现了回调时参数变化较大,
原来的接口返回标准是:一个请求无论请求的目的是否达到(比如,这个请求是用户注册是否成功)只要请求成功,后台则返回http状态码为200,通过响应体中包含的信息来进一步描述这个用户注册成功或者注册失败.
但是新版的接口返回标准改为:一个请求的目的达到与否直接影响到http状态码的返回,比如,同样是请求用户注册:

  • 如果注册成功,则后台返回http状态码为200.如果有其他信息则进一步在响应体中描述.
  • 如果注册失败(用户注册的目的没有达到)则后台的返回http状态码为400(甚至所有没有达到目的请求都会返回http状态码为400),而在在响应体中进一步用信息描述请求没有达到的原因,比如errorcode=4000001为用户已存在,errorcode=4000002...,errorcode=4000002....等等.前端则依照这个errorcode给用户以相应的提示.

问题:

那么问题来了,在AFNetworking的封装中会判断http状态码是否为200,如果是则进行successBlock的回调,回调参数中的responseObject则是响应体.如果是400的状态码,则进行failure的回调,而这个回调中参数只有这两个:

(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error)

我去,那我怎么拿到响应体啊?我需要响应体里的errorcode来区分是哪个错误才能提示用户啊.

分析:

首先在苹果原生的NSURLSession中只要是网络请求都会有响应头和响应体,
以下是一个标准的NSURLSession请求回调:

NSURLSessionDataTask *dataTask = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
  NSHTTPURLResponse *response = (NSHTTPURLResponse *)task.response;       
  NSInteger statusCode = response.statusCode;
  NSLog(@"http状态码:%ld", statusCode);
  NSLog(@"响应体信息:%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
}];

这里的statusCode就是http状态码.而响应体信息就是回调的data,那么既然AFNetworking的封装没有回调data,我又需要data,难道要我换掉AFNetworking的网络框架么?这太蠢了.或者在AFNetworking的failure中再次用NSURLSessionDataTask再次请求这个借口从而获得data么?这个也很蠢,因为同样的接口要请求两遍,耗时自然是double,而且会消耗大量的资源.正在思考这解决方法时,打印出来的error错误信息提醒了我.研究了一番error感觉回调的响应体数据是有长度,不过我确定那个究竟是error相关信息还是请求的响应体.点开NSERROR类

@interface NSError : NSObject  {
    @private
    void *_reserved;
    NSInteger _code;
    NSString *_domain;
    NSDictionary *_userInfo;
}

你会发现有个叫userInfo的成员变量,而在这个成员中,包含着若干个键值对,其中有个key叫做

@"com.alamofire.serialization.response.error.data"

这个key对应的value是一串data类型的数据,ok,我们把这个data转换成NSString类型打印出来一看,正是返回的响应体数据,其中就包括了需要的errorcode.这样的处理方式就做到在一次请求中,无论请求目的是否达到,都能获得请求的响应体信息从而正确的提醒用户.

解决问题&show me code


errorBlock:^(NSURLSessionDataTask * _Nullable __strong task, NSError * _Nonnull error) {
    NSHTTPURLResponse *response = (NSHTTPURLResponse *)task.response;
    NSInteger statusCode = response.statusCode;
    //如果响应头http状态码是400了则进一步查下原因
    if (statusCode == 400) {
        NSData *errorData = error.userInfo[@"com.alamofire.serialization.response.error.data"];
        NSDictionary *errorDataDict = [NSJSONSerialization JSONObjectWithData:errorData options:NSJSONReadingMutableLeaves error:nil];
        NSLog(@"400请求后进一步查询响应体:%@",errorDataDict);
        NSArray *allKeys = [errorDataDict allKeys];
        if ([allKeys containsObject:@"errorCode"]) {
            NSInteger errorCode = [errorDataDict[@"errorCode"] integerValue];
            //此处写根据errorCode对用户提醒弹窗(如果你用hud记得回调回主线程)或者回调.......
        } 
}

一点小tips:

  • @"com.alamofire.serialization.response.error.data"这个key只会出现在有响应体存在情况下的error.userInfo中,不用担心其他error的时候会取到奇怪的东西,同样的当出现其他类似的key的时候也可以关注一下,看看会有什么样的错误结果.
  • 其实NSError这个类的功能非常强大,如果遇到有报错的时候可以花时间研究下错误信息,没准就找到解决之道了,尤其是其中的error.userInfo.再不行通过error.code去查也更快更方便.
  • 最后,如有错误,恳请斧正.

你可能感兴趣的:(关于AFNetWorking3.0在failure回调时获取响应体信息)