ASIFormDataRequest en AFNetworking?

Tengo un código en ASIHTTP, pero quiero avanzar en AFNetworking. Utilicé ASIFormDataRequest para algunas requestes POST y este código funciona bien:

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]); } 

pero, cuando intenté hacer lo mismo con AFNetworking, tuve un problema con el tipo de contenido (supongo).

Este es el código AFNetworking y no funciona:

  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]; 

La URL está bien, esto está marcado. Estoy recibiendo del server esto:

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

El problema que está teniendo es porque está instanciando una AFJSONRequestOperation, que por defecto espera un tipo de respuesta amigable con JSON. ¿Estás esperando una respuesta JSON? De lo contrario, debe usar una class de request less específica. Por ejemplo, puede usar 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]; 

Si tiene types de request / respuesta más específicos (JSON, XML, etc.), puede usar esas subclasss AFHTTPRequestOperation específicas. De lo contrario, solo usa el vainilla HTTP.

Hace poco pasé lo mismo que tú. Aquí hay una class personalizada que escribí para manejar prácticamente cualquier request de networking.

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 

Esto agrega un par de características que puede que no necesite o desee, puede modificarlo según lo necesite, siempre que la sección de Copyright permanezca en su lugar. Utilizo esa APIKey para validar la request que vino de mi aplicación y no alguien que intenta hackear cosas.

Llamarlo (suponiendo que haya incluido 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. } }]; 

También puede:

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

Por lo tanto, tomará cualquier cantidad de parameters, inyecta una APIKey o cualquier otra cosa si desea y devuelve un Diccionario o una Matriz según el service web. Esto sí lo espera SBJson BTW.