我在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}
答案 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
这增加了一些您可能不需要或不想要的功能,只要版权部分保留在原地,您可以随意修改它。我使用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或其他任何内容,并根据Web服务返回字典或数组。这确实是SBJson BTW。