I've just started using the new AFNetworking 2.0
API having used the previous versions for a while now. I'm trying to do a bog standard http POST request
, but sadly I'm not doing too well. This is my current code:
AFHTTPRequestOperationManager *operationManager = [AFHTTPRequestOperationManager manager];
NSDictionary *parameters = @{@"username" : self.usernameField.text,
@"password" : self.passwordField.text};
[operationManager POST:@"https:URL GOES HERE" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"JSON: %@", [responseObject description]);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
}];
Now this returns a JSON
of (NULL)
and doesn't give me a status code like 404
or something (incidentally how do we attain the status code when using AFN 2.0?). However, when I try the information with a web app like apikitchen.com which tests the HTTP Post request
for me, it works when I put the username and password in the param
field. So really my question is, why don't the parameters
in the AFN 2.0 parameter property
act in the same way as the parameters
in the web app? And more generally why aren't the post request parameters
working for me in AFN 2.0
?
Thanks for the help in advance,
Mike
EDIT: I'm struggling with the implementation of the suggested fix. My Post method now looks like this, but It doesn't make sense to me right now.
AFHTTPRequestOperationManager *operationManager = [AFHTTPRequestOperationManager manager];
NSDictionary *parameters = @{@"username" : self.usernameField.text,
@"password" : self.passwordField.text};
operationManager.requestSerializer.queryStringSerializationWithBlock =
^NSString*(NSURLRequest *request,
NSDictionary *parameters,
NSError *__autoreleasing *error) {
NSString* encodedParams = form_urlencode_HTTP5_Parameters(parameters);
return encodedParams;
};
[operationManager POST:@"URL HERE" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"JSON: %@", [responseObject description]);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
}];
Now this returns a JSON of (NULL) and doesn't give me a status code like 404 or something (incidentally how do we attain the status code when using AFN 2.0?).
It should at least give an error. What does the failure handler print out?
So really my question is, why don't the parameters in the AFN 2.0 parameter property act in the same way as the parameters in the web app? And more generally why aren't the post request parameters working for me in AFN 2.0?
After examining how AFN (Version 2.0.1) encodes the parameters, it appears to me that these aren't encoded as they should: The application/x-www-form-urlencoded encoding algorithm.
Until this has been fixed, you may try the following workaround. The following algorithm encodes parameters strictly as suggested by w3c for HTTP 5, at least for Mac OS X 10.8 where I've tested it:
static NSString* form_urlencode_HTTP5_String(NSString* s) {
CFStringRef charactersToLeaveUnescaped = CFSTR(" ");
CFStringRef legalURLCharactersToBeEscaped = CFSTR("!$&'()+,/:;=?@~");
NSString *result = CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(
kCFAllocatorDefault,
(__bridge CFStringRef)s,
charactersToLeaveUnescaped,
legalURLCharactersToBeEscaped,
kCFStringEncodingUTF8));
return [result stringByReplacingOccurrencesOfString:@" " withString:@"+"];
}
(Note: the code above depends on the implementation details of function CFURLCreateStringByAddingPercentEscapes
. It's entirely possible to implement the suggested algorithm easily without any dependencies, which I would recommend - it becomes just not that short.)
static NSString* form_urlencode_HTTP5_Parameters(NSDictionary* parameters)
{
NSMutableString* result = [[NSMutableString alloc] init];
BOOL isFirst = YES;
for (NSString* name in parameters) {
if (!isFirst) {
[result appendString:@"&"];
}
isFirst = NO;
assert([name isKindOfClass:[NSString class]]);
NSString* value = parameters[name];
assert([value isKindOfClass:[NSString class]]);
NSString* encodedName = form_urlencode_HTTP5_String(name);
NSString* encodedValue = form_urlencode_HTTP5_String(value);
[result appendString:encodedName];
[result appendString:@"="];
[result appendString:encodedValue];
}
return [result copy];
}
Then, when using AFN, you can customize the serializing algorithm as shown below:
AFHTTPRequestOperationManager *operationManager = [AFHTTPRequestOperationManager manager];
operationManager.requestSerializer.queryStringSerializationWithBlock =
^NSString*(NSURLRequest *request,
NSDictionary *parameters,
NSError *__autoreleasing *error) {
NSString* encodedParams = form_urlencode_HTTP5_Parameters(parameters);
return encodedParams;
};
Put /
after the url. I've missed it for hours.