由AFN網(wǎng)絡(luò)請(qǐng)求失敗不曾返回錯(cuò)誤信息引發(fā)的思考:
業(yè)務(wù)場景:
-
前置條件:
我們的服務(wù)端給我們返回接口請(qǐng)求失敱炯ァ(比如說參數(shù)錯(cuò)誤等)是在AFN的success回調(diào)中獲取的,是一個(gè)名為
Result
的Model
鲁冯,里面有ResultCode
屬性和一個(gè)ResultDesc
屬性拷沸。客戶端所有的提示都是直接提示resultDesc薯演。 -
問題:
問題出現(xiàn)在登錄中撞芍,當(dāng)用戶輸錯(cuò)N次密碼后賬戶將被鎖定,無法登錄涣仿。輸入賬號(hào)密碼登錄應(yīng)當(dāng)提示
賬戶已被鎖定
勤庐,但是我們調(diào)用接口后只能獲得http的錯(cuò)誤碼401,無法獲得服務(wù)端提供給我們的Result好港。 -
查看:
經(jīng)過斷點(diǎn)查看愉镰,其實(shí)服務(wù)端是返回給我們相應(yīng)的錯(cuò)誤碼的,問題在于AFN在error回調(diào)中并不會(huì)將responseObject返回給我們钧汹,返回給我們的只有
(dataTask, error)
丈探。代碼如下(AFHTTPSessionManager.m 中的POST方法):
(NSURLSessionDataTask*)dataTaskWithHTTPMethod:(NSString*)method
URLString:(NSString*)URLString
parameters:(id)parameters
uploadProgress:(nullablevoid(^)(NSProgress*uploadProgress)) uploadProgress
downloadProgress:(nullablevoid(^)(NSProgress*downloadProgress)) downloadProgress
success:(void(^)(NSURLSessionDataTask*, id))success
failure:(void(^)(NSURLSessionDataTask*, NSError*))failure
{
NSError*serializationError=nil;
NSMutableURLRequest*request=[self.requestSerializerrequestWithMethod:methodURLString:[[NSURLURLWithString:URLStringrelativeToURL:self.baseURL] absoluteString] parameters:parameterserror:&serializationError];
if(serializationError) {
if(failure) {
dispatch_async(self.completionQueue?: dispatch_get_main_queue(), ^{
failure(nil, serializationError);
});
}
?
returnnil;
}
?
__blockNSURLSessionDataTask*dataTask=nil;
dataTask=[selfdataTaskWithRequest:request
uploadProgress:uploadProgress
downloadProgress:downloadProgress
completionHandler:^(NSURLResponse*__unusedresponse, idresponseObject, NSError*error) {
if(error) {
if(failure) {
failure(dataTask, error);
}
} else{
if(success) {
success(dataTask, responseObject);
}
}
}];
?
returndataTask;
}
- 解決方法:
經(jīng)過查找資料發(fā)現(xiàn)我們可以在error中獲得服務(wù)器返回的信息。
NSData*errorData=[error.userInfoobjectForKey:AFNetworkingOperationFailingURLResponseDataErrorKey];
NSDictionary*dic=[NSJSONSerializationJSONObjectWithData:errorDataoptions:NSJSONReadingAllowFragmentserror:nil];
Error 的返回包括了下述三個(gè)字段拔莱,都可以在error.userInfo中取出碗降,其中的AFNetworkingOperationFailingURLResponseDataErrorKey就是我們需要的錯(cuò)誤信息隘竭。將其轉(zhuǎn)化為DIctionary就可以獲取我需要的值了。
NSString*constAFURLResponseSerializationErrorDomain=@"com.alamofire.error.serialization.response";
NSString*constAFNetworkingOperationFailingURLResponseErrorKey=@"com.alamofire.serialization.response.error.response";
NSString*constAFNetworkingOperationFailingURLResponseDataErrorKey=@"com.alamofire.serialization.response.error.data";
思考
為什么失敗信息會(huì)在成功回調(diào)和失敗回調(diào)中都返回讼渊,這樣的話AFN區(qū)分成功回調(diào)和失敗回調(diào)有什么意義呢动看?
問了公司大佬得到的解釋:
我說到的兩種錯(cuò)誤信息是不同的,錯(cuò)誤信息包括網(wǎng)絡(luò)錯(cuò)誤信息和業(yè)務(wù)錯(cuò)誤信息爪幻。
- 網(wǎng)絡(luò)錯(cuò)誤由http返回菱皆,有一個(gè)統(tǒng)一的行業(yè)標(biāo)準(zhǔn),從1xx到5xx挨稿,基本涵蓋了所有的錯(cuò)誤仇轻。http錯(cuò)誤碼解析 。
- 業(yè)務(wù)錯(cuò)誤千奇百怪奶甘,就無法一一羅列形成統(tǒng)一的行業(yè)標(biāo)準(zhǔn)篷店,所以在200里返回一個(gè)
result
模型,包含resultCode和ResultDesc臭家。
為了適應(yīng)公司的需求疲陕,我們認(rèn)為把AFN提供的success
和failure
的回調(diào)合成一個(gè)completionHandler
,返回信息包括responseObject會(huì)更合適一點(diǎn)侣监。最后封裝成如下的方式:
+(NSURLSessionTask*) doPost:(AFHTTPSessionManager*) manageUrl:(NSString*) urlParams:(NSDictionary*) paramsCompletionHandler:(void(^)(NSURLSessionDataTask*task, idresponseObject)) completionHandler{
return[managePOST:urlparameters:paramsprogress:nilsuccess:^(NSURLSessionDataTask*_Nonnulltask, id _NonnullresponseObject) {
completionHandler(task, responseObject);
} failure:^(NSURLSessionDataTask*_Nullabletask, NSError*_Nonnullerror) {
NSData*errorData=[error.userInfoobjectForKey:AFNetworkingOperationFailingURLResponseDataErrorKey];
NSDictionary*dic=[NSJSONSerializationJSONObjectWithData:errorDataoptions:NSJSONReadingAllowFragmentserror:nil];
completionHandler(task, dic);
}];
}