ASIFormDataRequest в AFNetworking? - PullRequest
       25

ASIFormDataRequest в AFNetworking?

3 голосов
/ 03 апреля 2012

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

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}

Ответы [ 2 ]

4 голосов
/ 03 апреля 2012

Проблема в том, что вы создаете экземпляр AFJSONRequestOperation, который по умолчанию ожидает JSON-дружественный тип ответа.Ожидаете ли вы ответ JSON?Если нет, вам следует использовать менее специфичный класс Request.Например, вы можете использовать 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.

1 голос
/ 03 апреля 2012

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

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.

...