AFNetworking中的ASIFormDataRequest?

时间:2012-04-02 23:04:26

标签: objective-c ios asihttprequest afnetworking

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

网址很好,这是检查。 我从服务器那里得到了这个:

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

2 个答案:

答案 0 :(得分:4)

您遇到的问题是因为您正在实例化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子类。否则,只需使用vanilla HTTP。

答案 1 :(得分: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

这增加了一些您可能不需要或不想要的功能,只要版权部分保留在原地,您可以随意修改它。我使用API​​Key来验证来自我的应用程序的请求,而不是有人试图破解的东西。

调用它(假设您已包含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或其他任何内容,并根据Web服务返回字典或数组。这确实是SBJson BTW。