2013-10-11 8 views
8

Я использую AFNetworking 2.0 в своем приложении. Я заметил, что если мой веб-сервис возвращает код состояния 500, я не получаю тело ответа.AFNetworking 500 тело ответа

Вот пример моего кода 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()); 
} 

Если я использую простой клиент остального этот пример тела ответа.

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

Однако это, кажется, единственный ответ, который я могу получить от 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.} 

Это часть моей Objective-C код, который делает это.

...} failure:^(NSURLSessionDataTask *task, NSError *error) { 

     NSLog(@"%@",error.description); 

    }]; 

Есть ли способ получить тело ответа?

Edit: Подробнее Код для осветления

Ниже часть моего подкласса AFHTTPSessionManager

@implementation MSMAMobileAPIClient 

    + (MSMAMobileAPIClient *)sharedClient { 
     static MSMAMobileAPIClient *_sharedClient = nil; 
     static dispatch_once_t onceToken; 
     dispatch_once(&onceToken, ^{ 
      _sharedClient = [[MSMAMobileAPIClient alloc] initWithDefaultURL]; 
     }); 

     return _sharedClient; 
    } 

    - (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; 
    } 

Я попытался установить сериалайзер ответ на AFCompoundResponseSerializer, но это не похоже, чтобы сделать разницу

Ниже приведен пример подкласса, который я называю Библиотекарем.

-(void)searchForItemWithString:(NSString *)searchString withCompletionBlock:(arrayBlock)block { 

    self.inventorySearchBlock = block; 

    NSDictionary *parameters = @{@"query": searchString}; 

    [[MSMAMobileAPIClient sharedClient] 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); 

    }]; 

} 

ответ

14

UPDATE: Я создал репозиторий github, содержащий последний код, который я использую. Все изменения будут опубликованы там. https://github.com/Hackmodford/HMFJSONResponseSerializerWithData

Ответ исходит из этой проблемы на github. https://github.com/AFNetworking/AFNetworking/issues/1397

gfiumara - разработчик, который придумал это. Я лишь слегка изменил свой подкласс AFJSONResponseSerializer включать фактическую строку вместо 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 

Вот пример того, как я использую его в блоке отказа.

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

Помните, что установка значения 'nil' в' userInfo [JSONResponseSerializerWithDataKey] 'приведет к исключению. обходите это, используйте KVC. setValue: forKey: 'сначала проверяет значение, если это' nil'. Если это так, он обрабатывает инструкцию так, как если бы вы вызвали 'removeObject ForKey: вместо этого, который будет изящно ничего не делать, если объекта нет. – Baub

+0

@ Джеймс, ты предлагаешь это вместо этого? [userInfo setValue: [[NSString alloc] initWithData: кодировка данных: NSUTF8StringEncoding] forKey: JSONResponseSerializerWithDataKey]; – Hackmodford

+0

Именно так. – Baub

0

Вы должны использовать AFCompoundSerializer сказать рамки AFNetworking, как обрабатывать все возможные ответы он может получить. По умолчанию он попытается отобразить JSON. Составной сериализатор будет работать через сериализаторы, пока не найдет тот, который не вызывает ошибку.


Вы хотите использовать:

+ (instancetype)compoundSerializerWithResponseSerializers:(NSArray *)responseSerializers 

на AFCompoundResponseSerializerAFURLResponseSerialization.h).

Вам необходимо передать массив сериализаторов, которые могут обрабатывать ответ. Один из сериализаторов в массиве должен быть экземпляром AFHTTPResponseSerializer для обработки ваших ответов об ошибках.

+0

Есть ли урок об этом где-нибудь? – Hackmodford

+0

Страница AFNetworking github (в частности, руководство по миграции) - это место, где нужно идти. – Wain

+0

Я добавил пример моего подкласса AFHTTPSessionManager. Я неправильно настроил AFCompoundSerializer? – Hackmodford

0

Если включить мою категорию в вашем проекте, это так просто, как:

[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 ... 
}]; 

Вот код для моей категории. Он запускает AFURLSessionManager для вставки прокладки в обработчик завершения. Прокладка помещает ответ в пользовательскую информацию NSError.

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

Смежные вопросы