AFNetworking 500 cuerpo de respuesta

He estado usando AFNetworking 2.0 en mi aplicación. Me he dado count de que si mi service web devuelve un código de estado 500, no obtendré el cuerpo de la respuesta.

Aquí hay un ejemplo de mi código php

try { $conn = new PDO( "sqlsrv:server=$serverName;Database = $database", $uid, $pwd); $conn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION ); return $conn; } catch( PDOException $e ) { $response->status(500); echo( "Connection Error: " . $e->getMessage() ); } 

Si utilizo un cliente de descanso simple, este es un ejemplo de un cuerpo de respuesta.

 Connection Error: SQLSTATE[08001]: [Microsoft][SQL Server Native Client 11.0]SQL Server Network Interfaces: Error Locating Server/Instance Specified [xFFFFFFFF]. 

Sin embargo, esta parece ser la única respuesta que puedo get de AFNetworking

 Error Domain=NSCocoaErrorDomain Code=3840 "The operation couldn't be completed. (Cocoa error 3840.)" (JSON text did not start with array or object and option to allow fragments not set.) UserInfo=0x15e58fa0 {NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.} 

Esta es la parte de mi código objective-c que hace esto.

 ...} failure:^(NSURLSessionDataTask *task, NSError *error) { NSLog(@"%@",error.description); }]; 

¿Hay alguna manera de get el cuerpo de respuesta?

Editar: Más código para aclaración

A continuación es parte de mi subclass de AFHTTPSessionManager

 @implementation MSMAMobileAPIClient + (MSMAMobileAPIClient *)shanetworkingClient { static MSMAMobileAPIClient *_shanetworkingClient = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _shanetworkingClient = [[MSMAMobileAPIClient alloc] initWithDefaultURL]; }); return _shanetworkingClient; } - (id)initWithDefaultURL { return [self initWithBaseURL:[NSURL URLWithString:[NSString stringWithFormat:@"https://%@/mamobile/index.php/" ,[[NSUserDefaults standardUserDefaults] stringForKey:@"serviceIPAddress"]]]]; } - (id)initWithBaseURL:(NSURL *)url { self = [super initWithBaseURL:url]; if (!self) { return nil; } self.responseSerializer = [AFCompoundResponseSerializer compoundSerializerWithResponseSerializers:@[[AFJSONResponseSerializer serializer], [AFHTTPResponseSerializer serializer]]]; return self; } 

Intenté configurar el serializador de respuesta en un AFCompoundResponseSerializer pero no pareció hacer una diferencia

A continuación se muestra un ejemplo de una subclass a la que llamo el Bibliotecario.

 -(void)searchForItemWithString:(NSString *)searchString withCompletionBlock:(arrayBlock)block { self.inventorySearchBlock = block; NSDictionary *parameters = @{@"query": searchString}; [[MSMAMobileAPIClient shanetworkingClient] GET:@"inventory/search" parameters:parameters success:^(NSURLSessionDataTask *task, id responseObject) { if (!responseObject) { NSLog(@"Error parsing JSON"); } else { //do stuff with the json dictionary that's returned.. } } failure:^(NSURLSessionDataTask *task, NSError *error) { NSLog(@"Error: %@",error.description); }]; } 

ACTUALIZACIÓN: he creado un repository github para contener el último código que estoy usando. Todos los cambios se publicarán allí. https://github.com/Hackmodford/HMFJSONResponseSerializerWithData

La respuesta viene de este problema en github. https://github.com/AFNetworking/AFNetworking/issues/1397

gfiumara es el desarrollador que se le ocurrió esto. Solo he modificado ligeramente su subclass de AFJSONResponseSerializer para include una cadena real en lugar de la NSData

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

 // MSJSONResponseSerializerWithData.m #import "MSJSONResponseSerializerWithData.h" @implementation MSJSONResponseSerializerWithData - (id)responseObjectForResponse:(NSURLResponse *)response data:(NSData *)data error:(NSError *__autoreleasing *)error { if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) { if (*error != nil) { NSMutableDictionary *userInfo = [(*error).userInfo mutableCopy]; userInfo[JSONResponseSerializerWithDataKey] = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSError *newError = [NSError errorWithDomain:(*error).domain code:(*error).code userInfo:userInfo]; (*error) = newError; } return (nil); } return ([super responseObjectForResponse:response data:data error:error]); } @end 

Aquí hay un ejemplo de cómo lo uso en el bloque de falla.

 } failure:^(NSURLSessionDataTask *task, NSError *error) { NSLog(@"%@",[error.userInfo objectForKey:@"JSONResponseSerializerWithDataKey"]); }]; 

AFCompoundSerializer usar AFCompoundSerializer para decirle al marco de AFNetworking cómo procesar todas las respuestas posibles que podría recibir. De forma pnetworkingeterminada, solo intentará mapear JSON. Un serializador compuesto funcionará a través de los serializadores hasta que encuentre uno que no genere un error.


Desea usar:

 + (instancetype)compoundSerializerWithResponseSerializers:(NSArray *)responseSerializers 

en AFCompoundResponseSerializer (en AFURLResponseSerialization.h ).

Debe pasar una serie de serializadores que pueden manejar la respuesta. Uno de los serializadores en la matriz debe ser una instancia de AFHTTPResponseSerializer para manejar sus respuestas de error.

Si incluye mi categoría en su proyecto, es tan simple como lo siguiente:

 [mySessionManager POST:@"some-api" parameters:params success:^(NSURLSessionDataTask *task, NSDictionary *responseObject) { ... } failure:^(NSURLSessionDataTask *task, NSError *error) { id responseObject = error.userInfo[kErrorResponseObjectKey]; ... do something with the response ... }]; 

Aquí está el código de mi categoría. Swizzles AFURLSessionManager para inyectar una cuña en el controller de finalización. El calce pone la respuesta en UserInfo del NSError.

https://gist.github.com/chrishulbert/35ecbec4b37d36b0d608