AFNetworking - Requests with ETag - objective-c

I am trying to do a request on a server, which responds with an Etag for cache purposes. I have written the following code for it, but the response for these calls is random most of the time i.e. sometimes response status code is 200 and some times 304(expected). Am I doing something wrong in my code or is there something specific with AFNetworking that I should keep in mind.!
NSURL *url = [NSURL URLWithString:#"http://ia.media-imdb.com/images/M/MV5BNzI0NTY5NzQwMV5BMl5BanBnXkFtZTcwOTQyNTA5OA##._V1._SY90_.jpg"];
NSMutableURLRequest *aRequest = [NSMutableURLRequest requestWithURL:url];
[aRequest setValue:#"\"61-smtLpBSL_SY90_#1\"" forHTTPHeaderField:#"If-None-Match"];
NSLog(#"headers: %#", aRequest.allHTTPHeaderFields);
AFImageRequestOperation *operation = [AFImageRequestOperation imageRequestOperationWithRequest:aRequest imageProcessingBlock:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
NSLog(#"%# %d", response.allHeaderFields, response.statusCode);
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
NSLog(#"Request failed with error: %#", error);
}];
[operation start];

I had the same problem, I managed to fix this by changing my request to
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]
cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData
timeoutInterval:60];

I have tried your code and I receive status 200 - OK which is like it should be.
Code 304 - Not modified, I wasn't able to get. I have tried running command several times fast and slow but I always get 200 as a response.
Do you have more details when exactly it happens that you get 304 as response code?
304 response code generally means that the content hasn't been modified and you should get original request that had 200 as a response included in it.
Here you can read a bit more about Etag: ETag vs Header Expires

I also had a problem with the Etag logic and AFNetworking. My problem was just the cachePolicy not correctly set...
var manager = AFHTTPRequestOperationManager()
manager.requestSerializer = AFHTTPRequestSerializer()
manager.requestSerializer.cachePolicy = NSURLRequestCachePolicy.ReloadIgnoringLocalCacheData
manager.requestSerializer.setValue(etag, forHTTPHeaderField: "If-None-Match")
manager.GET(fullPath, parameters: parameters, success: {}, failure: {}))
I hope it will help someone !

Related

Basic and OAuth Authentication headers at the same time

Is it possible to use Basic and OAuth authorization headers in the same request with AFNetworking (avoiding the overwriting) ?
I have this code:
NSURL *url = [NSURL URLWithString:#"https://www.infojobs.net/"];
AFOAuth2Client *OAuthClient = [[AFOAuth2Client alloc] initWithBaseURL:url clientID:kClientID secret:kClientSecret];
[OAuthClient registerHTTPOperationClass:[AFJSONRequestOperation class]];
[OAuthClient authenticateUsingOAuthWithPath:#"oauth/authorize" code:self.authorizationCode redirectURI:kInfoJobsRedirectURLString success:^(AFOAuthCredential *credential) {
NSLog(#"Credentials: %#", credential.accessToken);
if (![credential.accessToken isEqualToString:#""]) {
self.isAuthenticated = YES;
[AFOAuthCredential storeCredential:credential withIdentifier:#"kInfoJobsAccessToken"];
[[InfoJobsAPI sharedClient] setAuthorizationHeaderWithToken:credential.accessToken];
// (!) This overwrites the Authorization header set with the accessToken
[[InfoJobsAPI sharedClient] setAuthorizationHeaderWithUsername:kClientID password:kClientSecret];
success(credential);
}
} failure:^(NSError *error) {
NSLog(#"Error: %#", error.localizedDescription);
}];
And I need a request like this:
GET /api/1/application HTTP/1.1
Host: api.infojobs.net
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Authorization: OAuth 07d18fac-77ea-461f-9bfe-a5e9d98deb3d
....
But I can't set the "Basic" and "OAuth" Authorization headers in the same request because AFNetworking seems to overwrite this header as seen in documentation
It's possible to use "Basic" and "OAuth" in a same Authorization header, maybe splitting both with a "\n" ?
Thanks, and sorry for my poor english
Edit
Finally, I can use the "Basic" and "Oauth" authentications in the same header, this is the code:
[[InfoJobsAPI sharedClient] setAuthorizationHeaderWithUsername:kClientID password:kClientSecret];
AFOAuthCredential *credential = [AFOAuthCredential retrieveCredentialWithIdentifier:#"kInfoJobsAccessToken"];
NSMutableURLRequest *request = [self requestWithMethod:#"GET" path:#"/api/2/candidate" parameters:nil];
[request addValue:[NSString stringWithFormat:#"OAuth %#", credential.accessToken] forHTTPHeaderField:#"Authorization"];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
DLog(#"Response : %#",JSON);
}failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
DLog(#"Error : %#",error);
}];
[operation start];
According to the HTTP specification there can be only one Authorization header in a request. So the behavior the library is showing is correct according to that specification: the second call to setAuthorizationHeader... overwrites the previous one.
What you'll typically see in HTTP is that there is a handshaking phase, where the server tells the client what authorization protocols it can accept. The client can then choose from those protocols, which one it wants to use.

How would i create a GET method to a webserver with AFNetwork

I was wondering how i would get AFNetworking code to visit a link on my web server(PHP Script) and get the response data, and put it into a string?
Could anyone post an example of this?
Thanks alot!
here is the required code to get response from server using AFNETWorking.Just add AFNetworking Library and the Required frameWorks.After that use the below code.
NSURL *url = [[NSURL alloc] initWithString:#"http://itunes.apple.com/search?term=harry&country=us&entity=movie"];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
NSLog(#"JSON");
self.movies = [JSON objectForKey:#"results"];
[self.tbleView reloadData];
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
NSLog(#"Request Failed with Error: %#, %#", error, error.userInfo);
}];
self.movies is name of mutable Array you can use any name instead of this.
Also you can check here
https://github.com/AFNetworking/AFNetworking
AFHTTPRequests get passed default NSURLRequest objects. stock ones - no modification for AFNetwork
to build THAT see
How to add GET parameters to an ASIHttpRequest?

AFNetworking PUT and Delete with Rails

In looking at the AFNetworking documentation, the Put and Delete methods take in a path and a dictionary of parameters. I am using Rails as my backend which expects these two types to take the form of Put /object/1.json and Delete /object/1.json. Should I build up a path string by adding in the Id or do I send a Put or Delete with the Id as one of the params in the Dictionary?
Typically when I do with PUT and similar type HTTP requests when using AFNetworking is something like this:
// Create an HTTP client with your site's base url
AFHTTPClient *client = [AFHTTPClient clientWithBaseURL:[NSURL URLWithString:#"http://example.com"]];
// Setup the other parameters you need to pass
NSDictionary *parameters = #{#"username" : #"bob", #"password" : #"123456"};
// Create a NSURLRequest using the HTTP client and the path with your parameters
NSURLRequest *request = [client requestWithMethod:#"PUT" path:#"object/1.json" parameters:parameters];
// Create an operation to receive any response from the server
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
// Do stuff
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
// Handle error
}];
// Begin the operation
[operation start];
If you look in AFHTTPClient.h there are examples for how to format your base url and your paths. There's more information on these methods in the AFNetworking documentation

Resolve redirect of NSURL?

I have a shortened URL (e.g. t.co/12345678). I would like to resolve the redirect without having to the load the entire page via NSURLConnection. Obviously, I can get it by sending an NSURLConnection and awaiting the response but this loads the entire page first. I am only looking for the redirect URL. Is this possible? If so, how?
=============
Edit: For posterity, here is the solution, as suggested by amleszk.
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:shortenedURL
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:15.0f];
[request setHTTPMethod:#"HEAD"];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
NSURL *resolvedURL = [httpResponse URL];
NSLog(#"%#", resolvedURL);
}];
same method as this: finding the download size of a URL (Content-Length)
but you want the [NSURLResponse statusCode] = 301/302/303 and the
Location header here: Getting "Location" header from NSHTTPURLResponse

How to pass JSON request

I am new to AFNetworking framework. I try to send JSON request to the server to get JSON response, so i tried something like this:
NSURL *url = [NSURL URLWithString:#"http://data.mycity.gov/api/views/INLINE/rows.json?method=index"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setValue:[NSString stringWithFormat:#"application/json"] forHTTPHeaderField:#"Content-Type"];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
NSLog(#"Success");
} failure:^(NSURLRequest* req,NSHTTPURLResponse *req2, NSError *error,id mex) {
NSLog(#"Failed");
NSLog(#"%#",[error description]);
}];
[operation start];
So i always find my self into the failure block, with this error description:
Error Domain=com.alamofire.networking.error Code=-1011 "Expected status code in (200-299), got 400" UserInfo=0x7b58030 {NSErrorFailingURLKey=http://data.mycity.gov/api/views/INLINE/rows.json?method=index, NSLocalizedDescription=Expected status code in (200-299), got 400}
Any ideas? am i missing something?
Status Code of 400 means - Bad Request
The request could not be understood by the server due to malformed syntax. The client SHOULD NOT repeat the request without modifications.
When I try to go to that URL:
http://data.mycity.gov/api/views/INLINE/rows.json?method=index"
, I get a not found error
Make sure the API you are using is correct, if the web service returns JSON, you should be able to type that URL into your browser and get a JSON response.
It seems your server is returning 400, "Bad Request". Check that your URL is correct.
BTW your stringWithFormat is redundant. You can replace
[NSString stringWithFormat:#"application/json"]
with
#"application/json"