AFNetworking 2.0 AFHTTPSessionManager:如何获取失败块中的状态码和响应JSON?

当切换到AFNetworking 2.0时,AFHTTPClient已被AFHTTPRequestOperationManager / AFHTTPSessionManager取代(如迁移指南中所述)。 我在使用AFHTTPSessionManager时遇到的第一个问题是如何检索失败块中的响应正文?

这是一个例子:

[self.sessionManager POST:[endpoint absoluteString] parameters:params success:^(NSURLSessionDataTask *task, id responseObject) { // How to get the status code? } failure:^(NSURLSessionDataTask *task, NSError *error) { // How to get the status code? response? }]; 

在成功块中,我想检索响应的状态码。 在失败块中,我想要检索响应的状态码和内容(在这种情况下是描述服务器端错误的JSON)。

NSURLSessionDataTask有一个NSURLResponsetypes的响应属性,它没有statusCode字段。 目前我能够像这样检索statusCode:

 [self.sessionManager POST:[endpoint absoluteString] parameters:params success:^(NSURLSessionDataTask *task, id responseObject) { // How to get the status code? } failure:^(NSURLSessionDataTask *task, NSError *error) { NSHTTPURLResponse *response = (NSHTTPURLResponse *)task.response; DDLogError(@"Response statusCode: %i", response.statusCode); }]; 

但是这对我来说很难看。 而且还不能确定响应的身体。

有什么build议么?

您可以使用“AFNetworkingOperationFailingURLResponseDataErrorKey”键直接从AFNetworking访问“数据”对象,因此不需要对AFJSONResponseSerializer进行子类化。 您可以将数据序列化为可读的字典。 以下是获取JSON数据的一些示例代码:

  NSData *errorData = error.userInfo[AFNetworkingOperationFailingURLResponseDataErrorKey]; NSDictionary *serializedData = [NSJSONSerialization JSONObjectWithData: errorData options:kNilOptions error:nil]; 

以下是在“失败”块中获取状态代码的代码:

  NSHTTPURLResponse* r = (NSHTTPURLResponse*)task.response; NSLog( @"success: %d", r.statusCode ); 

经过几天的阅读和研究,它为我工作:

1)你必须build立你自己的AFJSONResponseSerializer的子类

文件:JSONResponseSerializerWithData.h:

 #import "AFURLResponseSerialization.h" /// NSError userInfo key that will contain response data static NSString * const JSONResponseSerializerWithDataKey = @"JSONResponseSerializerWithDataKey"; @interface JSONResponseSerializerWithData : AFJSONResponseSerializer @end 

文件:JSONResponseSerializerWithData.m

 #import "JSONResponseSerializerWithData.h" @implementation JSONResponseSerializerWithData - (id)responseObjectForResponse:(NSURLResponse *)response data:(NSData *)data error:(NSError *__autoreleasing *)error { id JSONObject = [super responseObjectForResponse:response data:data error:error]; if (*error != nil) { NSMutableDictionary *userInfo = [(*error).userInfo mutableCopy]; if (data == nil) { // // NOTE: You might want to convert data to a string here too, up to you. // userInfo[JSONResponseSerializerWithDataKey] = @""; userInfo[JSONResponseSerializerWithDataKey] = [NSData data]; } else { // // NOTE: You might want to convert data to a string here too, up to you. // userInfo[JSONResponseSerializerWithDataKey] = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; userInfo[JSONResponseSerializerWithDataKey] = data; } NSError *newError = [NSError errorWithDomain:(*error).domain code:(*error).code userInfo:userInfo]; (*error) = newError; } return (JSONObject); } 

2)在AFHTTPSessionManager中设置你自己的JSONResponseSerializer

 + (instancetype)sharedManager { static CustomSharedManager *manager = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ manager = [[CustomSharedManager alloc] initWithBaseURL:<# your base URL #>]; // *** Use our custom response serializer *** manager.responseSerializer = [JSONResponseSerializerWithData serializer]; }); return (manager); } 

资料来源: http : //blog.gregfiumara.com/archives/239

你可以得到这样的状态代码,阅读失败块…

  NSURLSessionDataTask *op = [[IAClient sharedClient] POST:path parameters:paramsDict constructingBodyWithBlock:^(id<AFMultipartFormData> formData) { } success:^(NSURLSessionDataTask *task, id responseObject) { DLog(@"\n============= Entity Saved Success ===\n%@",responseObject); completionBlock(responseObject, nil); } failure:^(NSURLSessionDataTask *task, NSError *error) { DLog(@"\n============== ERROR ====\n%@",error.userInfo); NSHTTPURLResponse *response = (NSHTTPURLResponse *)task.response; int statuscode = response.statusCode;} 

除了被接受的答案之外还有另一种方法。

AFNetworking正在调用你的失败块,没有任何响应对象,因为它认为发生了真正的失败(例如,可能是HTTP 404响应)。 它将404解释为错误的原因是因为404不在响应串行器所拥有的“可接受的状态码”的集合中(可接受码的默认范围是200-299)。 如果你添加了404(或者400,或者500,或者其他),那么这个代码的响应将被认为是可以接受的,并且会被路由到你的成功块,而不是被解码的响应对象

但404是一个错误! 我希望我的失败块被称为错误! 如果是这种情况,请使用接受的答案中提到的解决scheme: https : //github.com/AFNetworking/AFNetworking/issues/1397 。 但是考虑一下,如果你要提取和处理内容,那么404也许是成功的。 在这种情况下,您的失败块将处理真正的失败 – 例如无法parsing的域名,networking超时等。您可以轻松地在您的成功块中检索状态码,并相应地进行处理。

现在我明白了 – 如果AFNetworking将任何responseObject传递给失败块,这可能会非常好。 但事实并非如此。

  _sm = [[AFHTTPSessionManager alloc] initWithBaseURL: [NSURL URLWithString: @"http://www.stackoverflow.com" ]]; _sm.responseSerializer = [AFHTTPResponseSerializer new]; _sm.responseSerializer.acceptableContentTypes = nil; NSMutableIndexSet* codes = [NSMutableIndexSet indexSetWithIndexesInRange: NSMakeRange(200, 100)]; [codes addIndex: 404]; _sm.responseSerializer.acceptableStatusCodes = codes; [_sm GET: @"doesnt_exist" parameters: nil success:^(NSURLSessionDataTask *task, id responseObject) { NSHTTPURLResponse* r = (NSHTTPURLResponse*)task.response; NSLog( @"success: %d", r.statusCode ); NSString* s = [[NSString alloc] initWithData: responseObject encoding:NSUTF8StringEncoding]; NSLog( @"%@", s ); } failure:^(NSURLSessionDataTask *task, NSError *error) { NSLog( @"fail: %@", error ); }]; 

您可以使用“AFNetworkingOperationFailingURLResponseDataErrorKey”键直接从AFNetworking访问“数据”对象,因此不需要对AFJSONResponseSerializer进行子类化。 您可以将数据序列化为可读的字典。 这是一些示例代码:

  NSData *errorData = error.userInfo[AFNetworkingOperationFailingURLResponseDataErrorKey]; NSDictionary *serializedData = [NSJSONSerialization JSONObjectWithData: errorData options:kNilOptions error:nil]; 

在Swift 2.0中(如果你还不能使用Alamofire):

获取状态码:

 if let response = error.userInfo[AFNetworkingOperationFailingURLResponseErrorKey] as? NSHTTPURLResponse { print(response.statusCode) } 

获取响应数据:

 if let data = error.userInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] as? NSData { print("\(data.length)") } 

一些JSON REST API在错误响应中返回错误消息(例如Amazon AWS服务)。 我使用此函数从AFNetworking引发的NSError中提取错误消息:

 // Example: Returns string "error123" for JSON { message: "error123" } func responseMessageFromError(error: NSError) -> String? { do { guard let data = error.userInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] as? NSData else { return nil } guard let json = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments) as? [String: String] else { return nil } if let message = json["message"] { return message } return nil } catch { return nil } } 

您可以获取与NSError对象关联的userInfo字典,并遍历它以获得您所需的确切响应。 例如在我的情况下,我得到一个服务器的错误,我可以看到像ScreeShot的userInfo

ScreenShot显示AFNetworking错误