2013-09-30 18 views
50

AFHTTPClient, AFNetworking 2.0'a geçtiğinde AFHTTPRequestOperationManager/AFHTTPSessionManager tarafından değiştirildi (geçiş kılavuzunda belirtildiği gibi). AFHTTPSessionManager'ı kullanırken karşılaştığım ilk sorun, hata bloğundaki yanıtın gövdesini nasıl alacağımızdır? Ben yanıtın durum kodu almak istediğiniz başarı bloğunda AFNetworking 2.0 AFHTTPSessionManager: Hata kodu blokta durum kodu ve yanıtı nasıl elde edilir?

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

:

İşte bir örnek. Hata bloğunda, hem yanıtlayanın durum kodunu hem de içeriği (sunucu tarafında hatayı açıklayan bu durumda JSON olan) almak istiyorum.

NSURLSessionDataTask, statusCode alanı olmayan NSURLResponse türünde bir yanıt özelliğine sahiptir. Şu anda böyle statusCode almak mümkün değilim:

[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); 

}]; 

Ama bu bana çirkin görünüyor. Ve hala yanıt veren kişinin vücudunu anlayamıyor.

Herhangi bir öneriniz var mı?

+0

[AFURLSessionManager dataTaskWithRequest: completionHandler:]' hangi aynı NSURLResponse 'yi (ve oraya da göndermelisiniz) geçiyor –

+0

Bu durum statusCode'u nasıl alacağınızı gösteriyor. Ne yazık ki NSHTTPURLResponse, hata bloğunda gövdeyi/verileri içermiyor :( – Oleksandr

+0

Görevin AFNetworkingTaskDidFinishResponseDataKey bildiriminde bulunan userInfo anahtarında, yanıtın, AFNetworkingTaskDidFinishNotification bildirimine göz atması gibi görünüyor. –

cevap

0

NSError nesnesiyle ilişkili userInfo sözlüğüne ve ihtiyacınız olan yanıtı almak için aşağı doğru hareket ettirin. benim durumumda Mesela ben bir sunucudan bir hata alıyorum ve ben gibi userInfo görebilirsiniz ScreeShot içinde

ScreenShot displaying AFNetworking error

+1

Benim durumumda, aşağıdaki ekran görüntüsünden görebileceğiniz gibi detaylı bir userInfo sağlamaz. [Örnek Ekran] (https://dl.dropboxusercontent.com/u/7487971/Screen%20Shot%202013-10-01%20at%2012.53.07%20PM.png). – Oleksandr

+0

Bu, sunucunun gerekli içerik/verileri başarısızlık yanıt gövdesine eklemediği anlamına gelir. Sunucu tarafı geliştiricisinin, yanıt gövdesi – unspokenblabber

+0

'da istediğiniz verileri vermesini istemenizi öneririm, sunucu doğru yanıt gövdesini döndürür. AFNetworkingTaskDidFinishNotification'da (hata ayıklama nedenleriyle) görebiliyorum. – Oleksandr

12

Sen, başarısızlık bloğu okumak ... böyle durum kodunu alabilirsiniz

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

Kabul edilen yanıtın yanında başka bir yaklaşım var.

AFNetworking, hata bloğunu çağırıyor, herhangi bir yanıt nesnesini saðlar, çünkü gerçek bir hata oluþtuðuna inanýr (örneðin, örneðin, bir HTTP 404 cevabı). 404'ü bir hata olarak yorumlama nedeni, 404'ün yanıt serileştiricisi tarafından sahip olunan "kabul edilebilir durum kodları" setinde olmamasıdır (varsayılan kabul edilebilir kod aralığı 200-299'dur). Bu kümeye 404 (ya da 400, ya da 500 ya da her neyse) eklerseniz, o kodla bir yanıt kabul edilebilir olarak kabul edilir ve bunun yerine kodu çözülmüş yanıt nesnesi ile tamamlanır.

Ancak 404 bir hatadır! Hata bloğumun hatalar için çağrılmasını istiyorum! Durum buysa, kabul edilen cevapla belirtilen çözümü kullanın: https://github.com/AFNetworking/AFNetworking/issues/1397. Ancak içeriğin ayıklanması ve işlenmesi için bir 404'ün gerçekten bir başarı olduğunu düşünün. Bu durumda, hata bloğunuz gerçek arızaları ele alır - örn. Çözülemeyen alanlar, ağ zaman aşımları, vb. Başarı kodunuzdaki durum kodunu kolayca alabilir ve buna göre işlem yapabilirsiniz.

Şimdi anlıyorum - AFNetworking hata bloğuna herhangi bir responseObject geçirdiyse, bu çok hoş olabilir. Ama öyle değil.

_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); 


    }]; 
+1

tam olarak ihtiyacım olan şey, güzel. – kernix

13

birkaç gün boyunca okuma ve araştırma sonrasında Benim için çalıştı: JSONResponseSerializerWithData.h:

#import "AFURLResponseSerialization.h" 

/// NSError userInfo key that will contain response data 
static NSString * const JSONResponseSerializerWithDataKey = @"JSONResponseSerializerWithDataKey"; 

@interface JSONResponseSerializerWithData : AFJSONResponseSerializer 
@end 

1) AFJSONResponseSerializer

Dosya kendi alt sınıfı oluşturmak zorunda

Dosya: 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); 
} 
01 senin AFHTTPSessionManager içinde

2) Kurulum kendi 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); 
} 

Kaynak: http://blog.gregfiumara.com/archives/239

+0

benim için çalıştı. kolay ve temiz –

3

Çok orada “AFNetworkingOperationFailingURLResponseDataErrorKey” tuşunu kullanarak “verileri” AFNetworking doğrudan nesne erişebilir AFJSONResponseSerializer alt sınıflarına gerek yoktur. Verileri okunabilir bir sözlüğe serileştirebilirsiniz.

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

Muhtemelen bu yinelenen cevabı silmelisiniz ... Cevabınıza bir şey eklerken, lütfen yeni bir tane oluşturmak yerine mevcut olanı düzenleyin. –

+0

Bu cevap harika, yanıt dizisine ihtiyacınız varsa 'NSString * errString = [[NSString alloc] initWithData: errorData kodlaması kullanabilirsiniz: NSUTF8StringEncoding];' – Johnny

63

Sen “veri” erişmek AFJSONResponseSerializer sınıflara ihtiyaç yoktur bu yüzden “AFNetworkingOperationFailingURLResponseDataErrorKey” tuşunu kullanarak AFNetworking doğrudan itiraz edebilirsiniz: İşte bazı örnek kod verilmiştir. Verileri okunabilir bir sözlüğe serileştirebilirsiniz. İşte JSON Veri almak için örnek kod:

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

İşaretçi için teşekkürler! Bununla birlikte, bunun nispeten yeni bir ek (AFNetworking 2.4.0, 2014-09-03 tarihinde yayınlanmıştır) olduğu ve bu nedenle sorulan zamanda mevcut olmadığı dikkate alınmalıdır. @Olx: Bu şimdi kabul edilen cevap olmalı! –

2

Swift 2.0 (tabii hala Alamofire kullanamazsınız): Burada

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

Arıza bloğunda Durum kodu gönder koddur :

al durum kodu:

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

al cevabı veriler:Bazı JSON REST API'ları hata iletilerinde (örneğin, Amazon AWS hizmetleri) hata iletilerini döndürür. Bazı JSON REST API'ları hata iletilerinde hata yanıtlarını döndürür. Ben AFNetworking tarafından atılan edilmiş bir NSError gelen hata mesajı ayıklamak için bu işlevi kullanın:

bunu nasıl, `aşağı düşürmeden hiçbir temizleyici yolu yoktur temelde var
// 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 
    } 
}