AFNetworking3 請求失敗時框冀,獲取業(yè)務邏輯報文信息

寫在前面:在接口的設計上,一般來說都會有兩個 statusCode:一個代表通訊協(xié)議層面敏簿,一個代表業(yè)務層面明也。但是,在某些特定的場景惯裕,這兩者之間可能混淆温数。也就是說,程序需要在通訊失敗的情況下蜻势,獲取服務器返回給前端的一些報文信息撑刺。

  • 為什么會存在這樣的問題

1.正常情況下,交易應該是:通訊狀態(tài)碼(200)+業(yè)務邏輯狀態(tài)碼(自定義)去處理每只交易的握玛。但某個例存在够傍,通訊狀態(tài)碼(非200)+業(yè)務邏輯狀態(tài)碼(自定義)去處理某些特殊情況。

2.在AF3.0版本中 當交易處理完畢時挠铲,當http通訊協(xié)議級別上返回的狀態(tài)碼是200時冕屯,框架會將業(yè)務邏輯報文返回給上一層;在通訊失敗時拂苹,返回的是 錯誤信息安聘,并沒有將我們需要的報文返回給上一層。

  • 該問題適用的場景

報文來說明場景
  • AF2.0 醋寝,獲取服務器返回的錯誤信息

AFHTTPRequestOperation *operation =[[AFHTTPRequestOperation alloc]initWithRequest:request];
    [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
     {
        success(operation, responseObject);
         
     } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
      //通訊協(xié)議狀態(tài)碼
         NSInteger statusCode = operation.response.statusCode;
      //服務器返回的業(yè)務邏輯報文信息
         NSDictionary *dict = operation.responseObject;
          failure(operation,error);
     }];

為了簡潔上面的代碼刪除了一些公共方法搞挣,在af的失敗回調(diào)方法中带迟,operation的這兩個方法音羞,可以將服務器返回的信息幫你取到。
那么仓犬,為什么2.0會如此輕易完成目標呢嗅绰,我們不妨看一下其post方法是如何實現(xiàn)的

#pragma mark - AFHTTPRequestOperation
-(void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
                              failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
    // completionBlock is manually nilled out in AFURLConnectionOperation to break the retain cycle.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-retain-cycles"
#pragma clang diagnostic ignored "-Wgnu"
    self.completionBlock = ^{
        if (self.completionGroup) {
            dispatch_group_enter(self.completionGroup);
        }
//在這個位置 我們已經(jīng)找到了 請求完畢時處理方法
 dispatch_async(http_request_operation_processing_queue(), ^{
//當通訊失敗的時候,failure返回的是(self窘面,self.error)翠语,而這個self指代的當前對象是AFHTTPRequestOperation實例,在它的屬性方法中财边,存在responseObject肌括,因此2.0方法,天然的可以解決此類問題
            if (self.error) {
                if (failure) {
                    dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{
                        failure(self, self.error);
                    });
                }
            } else {
                id responseObject = self.responseObject;
                if (self.error) {
                    if (failure) {
                        dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{
                            failure(self, self.error);
                        });
                    }
                } else {
                    if (success) {
                        dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{
                            success(self, responseObject);
                        });
                    }
                }
            }

            if (self.completionGroup) {
                dispatch_group_leave(self.completionGroup);
            }
        });
    };
#pragma clang diagnostic pop
}

從源碼中酣难,我們可以發(fā)現(xiàn):當通訊失敗的時候谍夭,failure返回的是(self,self.error)憨募,而這個self指代的當前對象是AFHTTPRequestOperation實例紧索,在它的屬性方法中,存在responseObject菜谣,因此2.0版本珠漂,天然的可以解決此類問題

  • AF3.0 ,如何獲取服務器返回的部分信息

[manager POST:urlStr parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        success(manager,responseObject);
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
    NSHTTPURLResponse *response = (NSHTTPURLResponse*)task.response;
 //通訊協(xié)議狀態(tài)碼
    NSInteger statusCode = response.statusCode;
 //服務器返回的業(yè)務邏輯報文信息
    NSDictionary *json = __dataSource.loginTimeOutDic;
    failure(task,error);
   }];

在3.0版本中尾膊,通訊協(xié)議的狀態(tài)碼還是很容易獲取到的媳危。但是,業(yè)務邏輯報文就沒那么容易拿到了冈敛。這個問題济舆,我們可以往下研究一下3.0的實現(xiàn)代碼。
1.3.0版本的post請求方法

-(NSURLSessionDataTask *)POST:(NSString *)URLString
                    parameters:(id)parameters
                      progress:(void (^)(NSProgress * _Nonnull))uploadProgress
                       success:(void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success
                       failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure
{
//在這里發(fā)情了請求莺债,我們繼續(xù)往下探尋
    NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"POST" URLString:URLString parameters:parameters uploadProgress:uploadProgress downloadProgress:nil success:success failure:failure];

    [dataTask resume];

    return dataTask;
}
-(NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
                                       URLString:(NSString *)URLString
                                      parameters:(id)parameters
                                  uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgress
                                downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgress
                                         success:(void (^)(NSURLSessionDataTask *, id))success
                                         failure:(void (^)(NSURLSessionDataTask *, NSError *))failure
{
    NSError *serializationError = nil;
    NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
    if (serializationError) {
        if (failure) {
            dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
                failure(nil, serializationError);
            });
        }

        return nil;
    }
//在這個位置 我們找到了 post請求處理完畢時的回調(diào)方法
    __block NSURLSessionDataTask *dataTask = nil;
    dataTask = [self dataTaskWithRequest:request
                          uploadProgress:uploadProgress
                        downloadProgress:downloadProgress
                       completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
        if (error) {
            if (failure) {
//先使用一種low逼的方法 用一個全局變量將邏輯報文信息帶回
                __dataSource.loginTimeOutDic = responseObject;
//原因在這里滋觉,3.0版本并沒有將邏輯報文返回到上一頁面
                failure(dataTask, error);
            }
        } else {
            if (success) {
                success(dataTask, responseObject);
            }
        }
    }];

    return dataTask;
}

2.這種修改第三方成熟框架的方法,從個人開發(fā)經(jīng)驗來說齐邦,并不推崇椎侠。
當使用cocopods管理第三方工具的時候,并沒有辦法去修改第三方的框架措拇,當更新之后我纪,會出現(xiàn)代碼被覆蓋掉的問題。而且丐吓,修改這類代碼可能會出現(xiàn)意想不到的問題浅悉,雖然可以通過擴展的方式,不影響原代碼邏輯券犁,但畢竟是不方便术健。因此,我推薦用下面這種方法去實現(xiàn)粘衬,這個功能荞估。

[manager POST:urlStr parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        success(manager,responseObject);
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
    NSHTTPURLResponse *response = (NSHTTPURLResponse*)task.response;
 //通訊協(xié)議狀態(tài)碼
    NSInteger statusCode = response.statusCode;
 //服務器返回的業(yè)務邏輯報文信息
  NSString* errResponse = [[NSString alloc] initWithData:(NSData *)error.userInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] encoding:NSUTF8StringEncoding];
 NSDictionary *json = [self dictionaryWithJson_String:errResponse];
  failure(task,error);
   }];

注意咳促,在這里取值的userInfo,是根據(jù)post請求完畢處理的方法勘伺,下面發(fā)現(xiàn)的代理方法中跪腹,

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市飞醉,隨后出現(xiàn)的幾起案子冲茸,更是在濱河造成了極大的恐慌,老刑警劉巖缅帘,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件噪裕,死亡現(xiàn)場離奇詭異,居然都是意外死亡股毫,警方通過查閱死者的電腦和手機膳音,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來铃诬,“玉大人祭陷,你說我怎么就攤上這事∪は” “怎么了兵志?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長宣肚。 經(jīng)常有香客問我想罕,道長,這世上最難降的妖魔是什么霉涨? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任按价,我火速辦了婚禮,結果婚禮上笙瑟,老公的妹妹穿的比我還像新娘楼镐。我一直安慰自己,他們只是感情好往枷,可當我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布框产。 她就那樣靜靜地躺著,像睡著了一般错洁。 火紅的嫁衣襯著肌膚如雪秉宿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天屯碴,我揣著相機與錄音描睦,去河邊找鬼。 笑死窿锉,一個胖子當著我的面吹牛酌摇,可吹牛的內(nèi)容都是我干的膝舅。 我是一名探鬼主播嗡载,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼窑多,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了洼滚?” 一聲冷哼從身側響起埂息,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎遥巴,沒想到半個月后千康,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡铲掐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年拾弃,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片摆霉。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡豪椿,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出携栋,到底是詐尸還是另有隱情搭盾,我是刑警寧澤,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布婉支,位于F島的核電站鸯隅,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏向挖。R本人自食惡果不足惜蝌以,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望何之。 院中可真熱鬧饼灿,春花似錦、人聲如沸帝美。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽悼潭。三九已至庇忌,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間舰褪,已是汗流浹背皆疹。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留占拍,地道東北人略就。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓捎迫,卻偏偏與公主長得像,于是被迫代替她去往敵國和親表牢。 傳聞我的和親對象是個殘疾皇子窄绒,可洞房花燭夜當晚...
    茶點故事閱讀 43,465評論 2 348

推薦閱讀更多精彩內(nèi)容