AFNetworking - iOS Getting JSON When PHP Prints It - ios

I have just started using AFNetworking, but I can't seem to figure out how to get the following to work.
My URL points to a PHP file which has printed out data it retrieved from a database as JSON, but with AFNetworking I get the "Expected Content Type" error.
My code is the following but with a different URL.
NSURL *url = [NSURL URLWithString:#"http://www.example.com/json.php"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFJSONRequestOperation *operation = [AFJSONRequestOperation
JSONRequestOperationWithRequest:request
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id json) {
NSLog(#"JSON: %#", [json valueForKeyPath:#"results"]);
} failure:nil];
[operation start];

I figured it out! :D
<?php header("Content-type: text/json"); ?>
Put this at the top of your page before anything is printed on the screen and AFNetworking will recognise it as JSON

#Ashley Thanks for sharing this. I had the same problem and this resolved it. However it should be
header("Content-type: application/json");
and not as you state

Related

AFNetworking disable caching

I'm trying to get a JSON file from a server then display it in a table, this works fine, however, for some reason AFNetworking is caching the JSON file even after a app restart.
How can I disable this?
NSURL *url = [NSURL URLWithString:#"http://?json"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFJSONRequestOperation *operation = [AFJSONRequestOperation
JSONRequestOperationWithRequest:request
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id responseObject)
{
self.dataget = [responseObject objectForKey:#"data"];
[self.tableView reloadData];
}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id responseObject)
{
[HUD hideUIBlockingIndicator];
}];
[operation start];
The json file is probably not cached server side:
Cache-Control: no-cache[CRLF]
Cache behavior can be set on NSMutableURLRequest objects, with setCachePolicy:. Otherwise, the built-in shared NSURLCache will respect the caching behavior defined by the server (which I would recommend tuning and taking advantage of, rather than outright disregarding).
AFNetworking doesn't do any caching. Also, the "Cache-Control" HTTP header tells the client not to cache the page (ie. AFNetworking), not the server.
It sounds like your server is caching the JSON page.
AFNetworking doesn't cache anything. You should probably check the cache control headers of the response. If i am not wrong then your server is sending some cache control headers which NSUrlConnection is taking into consideration. I would recommend you to set the caching policy of NSURLRequest to NSURLRequestReloadIgnoringLocalCacheData before making request to server

AFNetworking getting HTML from rails

I am using AFNetworking to get JSON data from the server, but I am only getting back HTML and an error that says the following:
Expected content type {(
"text/json",
"application/json",
"text/javascript"
)}, got text/html, AFNetworkingOperationFailingURLResponseErrorKey=<NSHTTPURLResponse: 0x7592470>}
The code is as follows:
NSURL *url = [NSURL URLWithString:#"http://127.0.0.1:3000/games"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFJSONRequestOperation *operation;
operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request
success:^(NSURLRequest *req, NSHTTPURLResponse *response, id jsonObject){
NSLog(#"Response: %#", jsonObject);
}
failure:^(NSURLRequest *req, NSHTTPURLResponse *response, NSError *error, id jsonObject){
NSLog(#"Error: %#", error);
}];
[operation start];
I am using rails and the server sends back JSON when I access the page with curl. I want to force application/json to be requested, am I doing this wrong?
You probably need to tell the server what content type you want back.
Here's a common fix for this issue:
NSURL *url = [NSURL URLWithString:#"http://127.0.0.1:3000/games"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
If this doesn't work, you'll need to step through your server code to determine under what conditions it'll return JSON instead of HTML.

statusCode property not set AFJSONRequestOperation

I am using the following code to make a http request and get json response back from a server. However when I look at the response's statusCode, I get the error that statusCode property is not set. What needs to be done to set the statusCode property in response.
NSString * my_url_string = #"http://link-to-my-server";
NSURL *url = [NSURL URLWithString:my_url_string];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
if (response.statusCode == 200){
//I GET AN AERROR THAT statusCode IS NOT SET
Error notwithstanding, AFNetworking already made the check for a successful status code with its success/failure completion block distinction. That is to say, unless you want to differentiate between different successful status codes (200, 201, 204, etc.), you don't need to do this check yourself.

AFNetworking with AFHTTPClient with AFJSONRequestOperation // MIME-Type Issues

I've been trying to get a grip on AFHTTPClient in the specific instance of dispatching a request to a REST-based service that requires OAuth authentication. I have no problem with creating the OAuth authentication using GTMOAuth.
I can also successfully marshall parameters to dispatch the request and obtain a well-formed JSON response using a hand-cobbled NSMutableURLRequest and both AFJSONRequestOperation and an NSURLConnection. Those latter two mechanics were my sanity check that I was touching the service correctly.
I get a response using
[AFHTTPClient HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject)]
but no matter what — it's interpreted as text/plain. The returned object's class is __NCFData.
No bueno.
This bit of code doesn't want to return a response that's a dictionary of any sort.
- (IBAction) testFlickr {
// marshall parameters
NSString *urlStr = #"http://api.flickr.com/";
NSURL *url = [NSURL URLWithString:urlStr];
AFHTTPClient *client = [[AFHTTPClient alloc]initWithBaseURL:url];
[client registerHTTPOperationClass:[AFJSONRequestOperation class]];
[client setParameterEncoding:AFJSONParameterEncoding];
NSDictionary *params = [[NSDictionary alloc]initWithObjectsAndKeys:#"json", #"format", #"66854529#N00", #"user_id", #"1", #"jsoncallback", nil];
NSString *path = [[NSString alloc]initWithFormat:#"services/rest/?method=flickr.people.getPhotos"];
NSMutableURLRequest *af_request = [client requestWithMethod:#"GET" path:path parameters:params];
// flickrAuth instance variable is an instance of GTMOAuthAuthentication
[self.flickrAuth authorizeRequest:af_request];
[client setAuthorizationHeaderWithToken:[self.flickrAuth accessToken]];
[client setDefaultHeader:#"Accept" value:#"application/json"];
[client requestWithMethod:#"GET" path:path parameters:params];
LOG_FLICKR_VERBOSE(0, #"Can Authorize? %#", ([self.flickrAuth canAuthorize] ? #"YES":#"NO"));
LOG_FLICKR_VERBOSE(0, #"%#", client);
// first way of trying..
AFHTTPRequestOperation *af_operation = [client HTTPRequestOperationWithRequest:af_request success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSString *str = [[NSString alloc] initWithData:responseObject
encoding:NSUTF8StringEncoding];
LOG_FLICKR_VERBOSE(0, #"Weird af_operation semantics, but.. %#", str);
LOG_FLICKR_VERBOSE(0, #"Weird af_operation semantics returns %#", [responseObject class]);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
//
LOG_FLICKR_VERBOSE(0, #"Weird af_operation semantics, error.. %#", error);
}];
[af_operation start];
}
This request goes through okay. The response data itself is what I'd expect, but it is not any kind of dictionary class.
I'd rather keep to using methods of AFHTTPClient (as opposed to, for example, [AFJSONRequestOperation JSONRequestOperationWithRequest]) so I can use AFHTTPClient's Reachability methods and so forth.
Strangely (to me, at least) if I do the request like this:
NSMutableURLRequest *aj_request = [client requestWithMethod:#"GET" path:path parameters:params];
[self.flickrAuth authorizeRequest:aj_request];
AFJSONRequestOperation *aj_operation =
[AFJSONRequestOperation JSONRequestOperationWithRequest:af_request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
LOG_FLICKR_VERBOSE(0, #"AFJSONRequestOperation %#", JSON);
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
LOG_FLICKR_VERBOSE(0, #"AFJSONREquestOperation Error %#", error);
}];
[aj_operation start];
It fails with a "401" because it was expecting application/json in the response header and instead thinks it's received text/plain
But, if I do the request like this:
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[[NSURL alloc]initWithString:#"http://api.flickr.com/services/rest/?method=flickr.people.getPhotos&format=json&user_id=66854529#N00&nojsoncallback=1"]];
[self.flickrAuth authorizeRequest:request];
AFJSONRequestOperation *operation =
[AFJSONRequestOperation JSONRequestOperationWithRequest:request
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
LOG_FLICKR_VERBOSE(0, #"Success Flickr =========\n%# %#", JSON, [JSON valueForKeyPath:#"photos.total"]);
/////handler(JSON, nil);
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
LOG_FLICKR(0, #"URL Was %#", url);
LOG_FLICKR(0, #"Failed Flickr ==========\n%# %#", error, JSON);
/////handler(nil, error);
}];
[operation start];
It works fine, including nice JSON, dictionary-formed data.
In the first instance, I'm using AFHTTPClient to produce the NSMutableURLRequest. In the second instance, I'm creating the NSMutableURLRequest on my own. In both cases I'm using AFJSONRequestOperation to dispatch the request leaving the only culprit for the problem to (besides myself..) AFHTTPClient.
In the first example that I can get to work, it's not returning JSON-y data.
In the second example AFHTTPClient seems to create an NSMutableURLRequest that blatantly fails — but (AFAICT) the same URL succeeds when that URL is created "by hand" using [NSMutableURLRequest requestWithURL].
I wonder — what am I missing when using AFHTTPClient?
Help?
In your first code example, it looks like you're doing NSMutableURLRequest *af_request = [client requestWithMethod:#"GET" path:path parameters:params]; and then setting default headers afterwards. Default headers only get applied to requests created after they were specified. Maybe that's where things are going amiss.
Also, that 401 error may be complaining about its content type, but 401 is an error status code, meaning that you're unauthenticated.
I ended up removing all the header parameters to isolate the problem, but it made no difference. Examining the response quite closely gave me a clue. While Flickr does return "JSON" it is not Lint-free, it seems and requires a tweak to one of the parameters. I had been sending jsoncallback=1 but it should be nojsoncallback=1. Once I fixed that parameter AFJSONRequestOperation handles the response correctly and parses the JSON.
My final code looks like this (for others, n.b. the nojsoncallback=1 parameter)
- (IBAction)testFlickrAFJSON:(id)sender
{
// marshall parameters
NSString *urlStr = #"http://api.flickr.com/";
NSURL *url = [NSURL URLWithString:urlStr];
//NSDictionary *params = [[NSDictionary alloc]initWithObjectsAndKeys:#"json", #"format", #"66854529#N00", #"user_id", nil];
NSDictionary *params = [[NSDictionary alloc]initWithObjectsAndKeys:#"json", #"format", #"66854529#N00", #"user_id", #"1", #"nojsoncallback", nil];
NSString *path = [[NSString alloc]initWithFormat:#"services/rest/?method=flickr.people.getPhotos"];
AFHTTPClient *client = [[AFHTTPClient alloc]initWithBaseURL:url];
NSMutableURLRequest *af_request = [client requestWithMethod:#"GET" path:path parameters:params];
[self.flickrAuth authorizeRequest:af_request];
LOG_FLICKR_VERBOSE(0, #"Can Authorize? %#", ([self.flickrAuth canAuthorize] ? #"YES":#"NO"));
AFJSONRequestOperation *af_operation_2 = [AFJSONRequestOperation JSONRequestOperationWithRequest:af_request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
LOG_FLICKR_VERBOSE(0, #"AFJSONRequestOperation Alt %#", JSON);
LOG_FLICKR_VERBOSE(0,#"AFJSONRequestOperation Alt response MIMEType %#",[response MIMEType]);
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
LOG_FLICKR_VERBOSE(0, #"AFJSONREquestOperation Alt Error %#", error);
NSHTTPURLResponse *resp = [[error userInfo] valueForKey:AFNetworkingOperationFailingURLResponseErrorKey];
LOG_FLICKR_VERBOSE(0,#"AFJSONRequestOperation Alt Error response MIMEType %#",[resp MIMEType]);
}];
[af_operation_2 start];
}

Error with AFNetworking for JSON Parsing

I have the following code for JSON Parsing:
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"https://www.dropbox.com/s/qz16qyi3julygl9/facebook.json"]];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
NSLog(#"Request Success %#",[JSON class]);
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
NSLog(#"Request Failure Because %#",[error userInfo]);
}];
[operation start];
but I have Request Failure with the following error message:
NSErrorFailingURLKey = "https://www.dropbox.com/s/qz16qyi3julygl9/facebook.json";
NSLocalizedDescription = "Expected content type {(\n \"text/json\",\n \"application/json\",\n \"text/javascript\"\n)}, got text/html";
can somebody help me?
In my errorlog it prints "got text/html". So just add
[AFJSONRequestOperation addAcceptableContentTypes:[NSSet setWithObject:#"text/html"]]
It works.
[AFJSONRequestOperation addAcceptableContentTypes:#"text/plain"]
The above is deprecated from AFNetworking 2.x. Instead you can call the following on the instance of the AFHTTPRequestOperation as follows
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObject:#"text/plain"];
Where manager is your instance of AFHTTPRequestOperation.
Source: https://github.com/AFNetworking/AFNetworking/issues/1381
Because the link you provide doesn't hotlink the file. It links to an HTML page to download the file. Try going there in a browser...
Try this link instead: https://dl.dropbox.com/s/qz16qyi3julygl9/facebook.json?dl=1 No guarantees it will work though. A lot of companies frown on directly linking to files in this way.

Resources