2012-04-02 4 views
3

У меня есть код в ASIHTTP, но я хочу перейти на AFNetworking. я использовал ASIFormDataRequest для некоторых запросов POST и этот код работает отлично:ASIFormDataRequest в AFNetworking?

NSURL *url = [NSURL URLWithString:@"http://someapiurl"]; 
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url]; 
[request setPostValue:@"123" forKey:@"phone_number"]; 
[request startSynchronous]; 
NSError *error = [request error]; 
if (!error) { 
    NSLog(@"Response: %@", [[request responseString] objectFromJSONString]); 

} 

, но, когда я попытался сделать то же самое с AFNetworking, я в задаче с содержанием типа (я думаю).

Это AFNetworking код, и он не работает:

NSURL *url = [NSURL URLWithString:@"http://dev.url"]; 
    AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url]; 

    NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys: 
          @"123", @"phone_number", 
          nil]; 
    NSMutableURLRequest *request = [httpClient requestWithMethod:@"POST" path:@"/api/get_archive" parameters:params]; 
    [request setValue:@"application/x-www-form-urlencoded; charset=UTF8" forHTTPHeaderField:@"Content-Type"]; 

    AFHTTPRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest 
*request, NSHTTPURLResponse *response, id JSON) { 
       NSLog(@"Response: %@", JSON); 
      } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON){ 
       NSLog(@"Error: %@", error); 
      }]; 
      [operation start]; 

URL нормально, это проверяется. Я получаю от сервера это:

{NSErrorFailingURLKey=http://dev.thisapiurl, NSLocalizedDescription=Expected content type {(
    "text/json", 
    "application/json", 
    "text/javascript" 
)}, got text/html} 

ответ

4

Проблема, с которой вы сталкиваетесь, заключается в том, что вы создаете экземпляр AFJSONRequestOperation, который по умолчанию ожидает JSON-дружественный тип ответа. Ожидаете ли вы ответ JSON? Если нет, вы должны использовать менее специфичный класс запроса. Например, вы можете использовать HTTPRequestOperationWithRequest:.

NSURL *url = [NSURL URLWithString:@"http://dev.url"]; 
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url]; 

NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys: 
         @"123", @"phone_number", 
         nil]; 
NSMutableURLRequest *request = [httpClient requestWithMethod:@"POST" path:@"/api/get_archive" parameters:params]; 
[request setValue:@"application/x-www-form-urlencoded; charset=UTF8" forHTTPHeaderField:@"Content-Type"]; 

//Notice the different method here! 
AFHTTPRequestOperation *operation = [httpClient HTTPRequestOperationWithRequest:request 
    success:^(AFHTTPRequestOperation *operation, id responseObject) { 
      NSLog(@"Response: %@", responseObject); 
     } 
    failure:^(AFHTTPRequestOperation *operation, NSError *error){ 
      NSLog(@"Error: %@", error); 
     }]; 
//Enqueue it instead of just starting it. 
[httpClient enqueueHTTPRequestOperation:operation]; 

Если у вас есть более конкретные типы запросов/ответов (JSON, XML и т.д.), вы можете использовать эти специфические AFHTTPRequestOperation подклассы. В противном случае просто используйте ванильный HTTP-файл.

+0

Yap, вот что мне нужно. Благодаря! – dormitkon

+0

Что значит «ожидает JSON-дружественный тип ответа»? Мои веб-службы возвращают ответ JSON. Можете ли вы взглянуть на [этот вопрос] (http://stackoverflow.com/questions/14393131/afjsonrequestoperation-returns-null-response-in-ios) – iOSAppDev

+0

@jagill Что вы подразумеваете под «ожидает, что JSON-дружественный тип ответа "? Проверяет ли он Content-Type = application/json? – iOSAppDev

1

Я недавно прошел через то же самое, как вы. Вот специальный класс, который я написал для обработки практически любого сетевого запроса.

NetworkClient.h:

// 
// NetworkClient.h 
// 
// Created by LJ Wilson on 3/8/12. 
// Copyright (c) 2012 LJ Wilson. All rights reserved. 
// 

#import <Foundation/Foundation.h> 

extern NSString * const ACHAPIKey; 

@interface NetworkClient : NSObject 

+(void)processURLRequestWithURL:(NSString *)url 
         andParams:(NSDictionary *)params 
          block:(void (^)(id obj))block; 

+(void)processURLRequestWithURL:(NSString *)url 
         andParams:(NSDictionary *)params 
        syncRequest:(BOOL)syncRequest 
          block:(void (^)(id obj))block; 

+(void)processURLRequestWithURL:(NSString *)url 
         andParams:(NSDictionary *)params 
        syncRequest:(BOOL)syncRequest 
      alertUserOnFailure:(BOOL)alertUserOnFailure 
          block:(void (^)(id obj))block; 

+(void)handleNetworkErrorWithError:(NSError *)error; 

+(void)handleNoAccessWithReason:(NSString *)reason; 
@end 

NetworkClient.m:

// 
// NetworkClient.m 
// 
// Created by LJ Wilson on 3/8/12. 
// Copyright (c) 2012 LJ Wilson. All rights reserved. 
// 

#import "NetworkClient.h" 
#import "AFHTTPClient.h" 
#import "AFHTTPRequestOperation.h" 
#import "SBJson.h" 

NSString * const APIKey = @"APIKeyIfYouSoDesire"; 

@implementation NetworkClient 

+(void)processURLRequestWithURL:(NSString *)url 
         andParams:(NSDictionary *)params 
          block:(void (^)(id obj))block { 

    [self processURLRequestWithURL:url andParams:params syncRequest:NO alertUserOnFailure:NO block:^(id obj) { 
     block(obj); 
    }]; 
} 

+(void)processURLRequestWithURL:(NSString *)url 
         andParams:(NSDictionary *)params 
        syncRequest:(BOOL)syncRequest 
          block:(void (^)(id obj))block { 
    if (syncRequest) { 
     [self processURLRequestWithURL:url andParams:params syncRequest:YES alertUserOnFailure:NO block:^(id obj) { 
      block(obj); 
     }]; 
    } else { 
     [self processURLRequestWithURL:url andParams:params syncRequest:NO alertUserOnFailure:NO block:^(id obj) { 
      block(obj); 
     }]; 
    } 
} 


+(void)processURLRequestWithURL:(NSString *)url 
         andParams:(NSDictionary *)params 
        syncRequest:(BOOL)syncRequest 
      alertUserOnFailure:(BOOL)alertUserOnFailure 
          block:(void (^)(id obj))block { 

    // Default url goes here, pass in a nil to use it 
    if (url == nil) { 
     url = @"MyDefaultURLGoesHere"; 
    } 

    NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithDictionary:params]; 
    [dict setValue:APIKey forKey:@"APIKey"]; 

    NSDictionary *newParams = [[NSDictionary alloc] initWithDictionary:dict]; 

    NSURL *requestURL; 
    AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:requestURL]; 

    NSMutableURLRequest *theRequest = [httpClient requestWithMethod:@"POST" path:url parameters:newParams]; 

    __block NSString *responseString = [NSString stringWithString:@""]; 

    AFHTTPRequestOperation *_operation = [[AFHTTPRequestOperation alloc] initWithRequest:theRequest]; 
    __weak AFHTTPRequestOperation *operation = _operation; 

    [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { 
     responseString = [operation responseString]; 

     id retObj = [responseString JSONValue]; 

     // Check for invalid response (No Access) 
     if ([retObj isKindOfClass:[NSDictionary class]]) { 
      if ([[(NSDictionary *)retObj valueForKey:@"Message"] isEqualToString:@"No Access"]) { 
       block(nil); 
       [self handleNoAccessWithReason:[(NSDictionary *)retObj valueForKey:@"Reason"]]; 
      } 
     } else if ([retObj isKindOfClass:[NSArray class]]) { 
      NSDictionary *dict = [(NSArray *)retObj objectAtIndex:0]; 
      if ([[dict valueForKey:@"Message"] isEqualToString:@"No Access"]) { 
       block(nil); 
       [self handleNoAccessWithReason:[(NSDictionary *)retObj valueForKey:@"Reason"]]; 
      } 
     } 
     block(retObj); 
    } 
             failure:^(AFHTTPRequestOperation *operation, NSError *error) { 
              NSLog(@"Failed with error = %@", [NSString stringWithFormat:@"[Error]:%@",error]); 
              block(nil); 
              if (alertUserOnFailure) { 
               [self handleNetworkErrorWithError:operation.error]; 
              } 

             }]; 

    [operation start]; 

    if (syncRequest) { 
     // Only fires if Syncronous was passed in as YES. Default is NO 
     [operation waitUntilFinished]; 
    } 


} 


+(void)handleNetworkErrorWithError:(NSError *)error { 
    NSString *errorString = [NSString stringWithFormat:@"[Error]:%@",error]; 

    // Standard UIAlert Syntax 
    UIAlertView *myAlert = [[UIAlertView alloc] 
          initWithTitle:@"Connection Error" 
          message:errorString 
          delegate:nil 
          cancelButtonTitle:@"OK" 
          otherButtonTitles:nil, nil]; 

    [myAlert show]; 

} 

+(void)handleNoAccessWithReason:(NSString *)reason { 
    // Standard UIAlert Syntax 
    UIAlertView *myAlert = [[UIAlertView alloc] 
          initWithTitle:@"No Access" 
          message:reason 
          delegate:nil 
          cancelButtonTitle:@"OK" 
          otherButtonTitles:nil, nil]; 

    [myAlert show]; 

} 

@end 

Это добавляет несколько функций может не потребоваться или хотите, не стесняйтесь изменять его, как вам нужно до тех пор, поскольку раздел «Авторское право» остается в силе. Я использую этот APIKey для проверки запроса, который пришел из моего приложения, а не для того, чтобы кто-то пытался взломать вещи.

Назвав его (если вы включили NetworkClient.h:

NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys: 
          @"ParamValue1", @"ParamName1", 
          @"ParamValue2", @"ParamName2", 
          nil]; 


    [NetworkClient processURLRequestWithURL:nil andParams:params block:^(id obj) { 
     if ([obj isKindOfClass:[NSArray class]]) { 
      // Do whatever you want with the object. In this case, I knew I was expecting an Array, but it will return a Dictionary if that is what the web-service responds with. 
     } 
    }];  

Также можно:

NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys: 
          @"ParamValue1", @"ParamName1", 
          nil]; 

    NSString *urlString = @"https://SuppliedURLOverridesDefault"; 
    [NetworkClient processURLRequestWithURL:urlString 
            andParams:params 
           syncRequest:YES 
         alertUserOnFailure:NO 
             block:^(id obj) { 
              if ([obj isKindOfClass:[NSArray class]]) { 
               // Do stuff 
              } 
             }]; 

Так он будет принимать в любом количестве параметров, вводят в APIKey или что-нибудь еще, если вы хотите и верните обратно словарь или массив в зависимости от веб-сервиса. Это ожидает SBJson BTW.

+0

EIJay, thx для вашего ответа, но я хочу использовать инфраструктуру AFNetworking, потому что знаю, что она будет сохранена и станет лучше. Именно по этой причине я покидаю ASIHTTP – dormitkon

+0

Причины, по которым я покинул ASI, заключались в том, что AFNetworking использует блоки вместо методов делегирования и потому, что он никогда не будет совместим с ARC без переопределения. –

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