AFHTTPSessionManager calling localhost ip - ios

I'm trying to run my iOS app, having it pull data from the node.js server I have running locally.
The problem I'm having is that when I use AFHTTPSessionManager's GET method, it keeps on timing out.
I've tried doing the request from my browser and my locally running node server is returning the json as expected. I've also tried curling from the cl and it also returns as expected.
Is there something I'm missing?
Here's my test code:
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
[manager GET:#"http://192.168.33.327/api/v1/item" parameters:nil success:^(NSURLSessionDataTask *task, id responseObject) {
NSLog(#"JSON: %#", responseObject);
} failure:^(NSURLSessionDataTask *task, NSError *error) {
NSLog(#"Error: %#", error);
}];
I've also tried initializing the manager with a base url, then just passing in the path to GET but it still times out. (the error I get in error says the error code is -1001)
Also you'll notice there is no port number on the code I've pasted. at first I had it on port 8080, but thought that might be causing a problem, so I ran node on port 80 instead, but it still didn't help.
Thanks!

Related

Generating POST messages using AFNetworking?

So, I get JSON to return from my web service using a command like this in terminal:
curl --data 'method=my-service.search&document_type=x&keywords=y' http://mywebsite.com/services/json/my-service.search
And I've been trying to get this data through AFNetworking for parsing and use in an app. So far, this is what I have tried:
NSDictionary *parameters = [NSDictionary dictionaryWithObjectsAndKeys:#"document_type", #"keywords", nil];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:urlString parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject)
I set the URL string to http://mywebsite.com/services/json/my-service.search and the dictionary is supposed to contain the parameters for searching.
But I get an error saying that the request failed due to "unacceptable content-type: text/html" (obviously, it wants JSON).
So my question is as follows: How do you perform a cURL data request through AFNetworking?
I have a bonus question as well: how do you interact with the parameters in the dictionary (say, set the keyword field to "Stack Overflow" or something like that)?
Thanks for the help! I'm just starting out, so any advice would be appreciated.
You can specify content-type with this:
[manager.requestSerializer setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
But first of all make sure you set propert request serializer:
manager.requestSerializer = [AFJSONRequestSerializer serializer];
It should set content type automatically
Also use POST: instead of GET:

AFNetworking API call status code

Is there a possibility that AFNetworking takes API status code in consideration as well?
Call returns 200 HTTP code that it is ok, but status code is 406 which indicates failure.
This results to AFNetworking success block being called, even though API call failed.
Is there a solution to this?
Code:
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSString *APICallURL = [NSString stringWithFormat:#"%#/%#", SERVER_URL, #"something.php"];
[manager GET:APICallURL parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
if (success) {
success();
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if (failure) {
failure(error);
}
}];
X-API-Status-Code is a totally non-standard header (as any header starting with X-... actually, by definition).
That header is a proprietary way that your specific server chose to report the API status code. It could have picked any other proprietary header to do so, maybe calling it X-API-ReturnCodeor whatnot.
So I doubt that AFNetworking will ever support this natively.
But you can probably create your own AFURLResponseSerialization subclass and implement validateResponse, so that your code check for this proprietary header and act accordingly.
It will not reach failure block for any failure status code from server. With respect to AFNetworking, network call is successful with a error code from server.
It will reach failure block only when we are not able to successfully finish the network call, like
1) Time out error
2) Server down and not able to reach
3) Network loss etc
Solution is we should check the status code of network call in success block and identify error responses from server

Dealing with unexpected response content types with AFNetworking / AFHTTPRequestOperation

I'm using AFNetworking to process HTTP requests in my iOS app. I have run into a stumbling block. I cannot be certain of what the response content type will be, but you have to set the response serializer BEFORE the request is processed. This means I could do an API request, expecting an image back, but actually there's some authentication error, so the server returns a JSON-formatted response instead.
Here's my code:
AFHTTPRequestOperation* op = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[op setResponseSerializer:[AFJSONResponseSerializer serializer]]; // ??????
[op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSDictionary* result = (NSDictionary*) responseObject;
onSuccess((NSArray*) result);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
onFailure(error);
}];
[op start];
As you can see, I've had to set the expected content type implicitly by setting the responseSerializer to [AFJSONResponseSerializer serializer]. So if I get something else back, it causes an error, even though I may still wish to parse an process that response when dealing with the error.
So my question is, should I just use the standard AFHTTPResponseSerializer, examine the response status code and then process the response body manually (as json, xml, html an image etc)?
Set the accepted content types you want on the serialiser with acceptableContentTypes:
AFJSONResponseSerializer *serializer = [AFJSONResponseSerializer serializer];
serializer.acceptableContentTypes = [NSSet setWithArray:#[#"text/plain", #"text/html"]];
[op setResponseSerializer:serializer];
From the docs:
By default, AFJSONSerializer accepts the following MIME types, which
includes the official standard, application/json, as well as other
commonly-used types:
application/json
text/json
You don't have to use AFJSONResponseSerializer, as you can create your own serializer as long as it conforms to the AFURLResponseSerialization protocol.
If you have JSON responses but XML error responses, you could just subclass AFHTTPResponseSerializer and do your own processing in there.
You could also use AFCompoundResponseSerializer to parse different response types just going through the serializers you give it.
Your API is a little unusual: if you aren't authorized, it should just use an HTTP 401 response, not JSON. But there's plenty of unusual API's out there and I bet you don't have control over this one.
The fix is straightforward:
Make an implementation of AFURLResponseSerialization that just acts as a proxy, and assign that one as the serializer for your request. When the response comes in, have it take a quick look at the data and then instantiate and call the right serializer.

AFNetworking 2.0 - unexpected NSURLErrorDomain error -1012

We ran into the following issue with our app that uses AFNetworking 2.0.
When using AFHTTPRequestOperationManager's GET method, we got an error NSURLErrorDomain code -1012. The request used HTTPS and the server does not require user authentication. The request never reached the server by the way.
We have run several tests and this is the first time the error was produced and we are wondering how this error can get produced because it does not seem relevant.
Setup of AFHTTPRequestOperationManager :
httpOperationManager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:
[NSURL URLWithString: HTTPS_URL)]];
httpOperationManager.responseSerializer =
[AFXMLParserResponseSerializer serializer];
[[AFNetworkActivityIndicatorManager sharedManager] setEnabled: YES];
GET REQUEST
AFHTTPRequestOperation *op =[httpOperationManager GET:
[NSString stringWithFormat:SOME_PATH]
parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject) {
//code to setup NSXMLParser ...
}
failure: ^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"error %#", [error localizedDescription]);
}];
I think you already solved the problem, but if you are trying to authenticate in a server that doesn't have a valid certificate you have to set YES for property allowInvalidCertificates in your AFHTTPRequestOperationManager object:
[yourManager.requestSerializer setAuthorizationHeaderFieldWithUsername:#"your_username" password:#"your_password"];
[yourManager.securityPolicy setAllowInvalidCertificates:YES];
Also, as #a1phanumeric said, it can be necessary to include this line:
[yourManager.securityPolicy setValidatesDomainName:NO];
Cheers.
NSURLErrorDomain -1012 is NSURLErrorUserCancelledAuthentication. (See the error code list and search for -1012.)
You state, "the server does not require user authentication". But this error would not be called if that were true.
Possible causes:
Your server is erroneously requesting authorization (a server bug)
The URL formed with HTTPS_URL and SOME_PATH is not what you expect, and some other server is requesting authorization
Some intermediary (like a proxy server, or an access point) is requiring authorization.
Some debugging tips:
Set breakpoints inside the AFNetworking implementation to see which URL is being hit
Configure AFHTTPRequestOperationLogger so you can see the actual request body and response in your console log
Make the same request with curl or Advanced Rest Client and observe the server's response
Side note: I think [NSString stringWithFormat:SOME_PATH] is pointless - why not just use SOME_PATH?

Login form with AFNetworking 1.3

I am trying to login into a website through an HTML form using AFNetworking 1.3. I simply set my credentials and POST to the proper path. The problem is that I am not issued a cookie that states that I am logged in.
NSURL *baseURL = [NSURL URLWithString:#"https://mysite.edu"];
AFHTTPClient *client = [AFHTTPClient clientWithBaseURL:baseURL];
NSString *loginPath = #"/place/loginPage";
NSDictionary *loginParameters = #{#"sid" : #"username",
#"PIN" : #"12345678"};
NSMutableURLRequest *request = [client multipartFormRequestWithMethod:#"POST"
path:loginPath
parameters:loginParameters
constructingBodyWithBlock:nil];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"success: %#", operation.responseString);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"error: %#", operation.responseString);
}];
[operation start];
The web server is returning a webpage that states that I do not have cookies enabled:
This system requires the use of HTTP cookies to verify authorization information.
Our system has detected that your browser has disabled HTTP cookies, or does not support them.
Please refer to the Help page in your browser for more information on how to correctly configure your browser for use with this system.
However, if I iterate through my issued cookies, I find that the website has issued me cookies, but not a session cookie. Therefore my AFNetworking client really is accepting cookies? Is there a setting that I must adjust to allow session cookies to properly work with AFNetworking 1.3?
I have edited my HTTP request header to match working browsers such as Chrome.
[Is] my AFNetworking client really [] accepting cookies? Is there a setting that I must adjust to allow session cookies to properly work with AFNetworking 1.3?
AFNetworking has no cookie-specific configuration. Cookies are solely the responsibility of the Foundation URL Loading system.
Some possible solutions:
Install AFHTTPRequestOperationLogger and configure it with AFLoggerLevelDebug to see all HTTP headers. This will let you see what's actually getting sent and received in your Xcode console.
The server may be dropping the cookie, for example if it's a Ruby server with protect_from_forgery enabled. Check your server logs and this solution for information on disabling or sending the appropriate token.
You control how requests use cookies with -[NSMutableURLRequest setHTTPShouldHandleCookies]. Make sure this is set to YES (the default.)
Other apps can alter the Cookie Accept Policy, so make sure -[NSHTTPCookieStorage cookieAcceptPolicy] is returning NSHTTPCookieAcceptPolicyAlways (or NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain if you need it.)
Since I came here while searching for a working solution for AFNetworking 2.0, not knowing that AFHTTPClient was removed from the Framework, I will post the new way to establish this connection here:
AFHTTPRequestOperationManager *manager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:[NSURL URLWithString:#"http://examplewebsite.com"]];
[manager setRequestSerializer:[AFHTTPRequestSerializer serializer]];
[manager.requestSerializer setAuthorizationHeaderFieldWithUsername:#"userName" password:#"password"];

Resources