AFNetworking Expected status code in (200-299), got 403 - ios

Trying to migrate my code from ASIHttpRequest to AFNetworking. It seems similar questions has been asked but couldnt find solution to my problem.
My code was working fine with ASIHttpRquest.
I send a simple post request to my server and listen http responses. If http response is 200 everything works fine but if I send another status code >400 AFNetworking block fails.
Server side response:
$rc = $stmt->fetch();
if ( !$rc ) {
// echo "no such record\n";
$isrecordExist=0; //false does not exists
sendResponse(403, 'Login Failed');
return false;
}
else {
// echo 'result: ', $result, "\n";
$sendarray = array(
"user_id" => $result,
);
sendResponse(200, json_encode($sendarray));
}
IOS Part:
AFHTTPClient *client = [[AFHTTPClient alloc] initWithBaseURL:
[NSURL URLWithString:server]];
client.allowsInvalidSSLCertificate=YES;
[client postPath:loginForSavingCredientials parameters:params success:^(AFHTTPRequestOperation *operation, id response) {
if (operation.response.statusCode == 500) {}
else if (operation.response.statusCode == 403) {}
else if (operation.response.statusCode == 200) {//able to get results here NSError* error;
NSString *responseString = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
NSDictionary* json = [NSJSONSerialization JSONObjectWithData: [responseString dataUsingEncoding:NSUTF8StringEncoding]
options: NSJSONReadingMutableContainers
error: &error];}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"failure %#", [error localizedDescription]);
}];
NSLOG:
failure Expected status code in (200-299), got 403
How can I fix this?

When AFNetworking gets a 2xx (success) status code, it calls the success block.
When it gets a 4xx (client error) or 5xx (server error) status code, it calls the failure block because something went wrong.
So all you should need to do is move your check for a 500 or 403 status code to the failure block.
AFHTTPClient *client = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:server]];
client.allowsInvalidSSLCertificate=YES;
[client postPath:loginForSavingCredientials parameters:params success:^(AFHTTPRequestOperation *operation, id response) {
if (operation.response.statusCode == 200) {//able to get results here NSError* error;
NSString *responseString = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
NSDictionary* json = [NSJSONSerialization JSONObjectWithData: [responseString dataUsingEncoding:NSUTF8StringEncoding]
options: NSJSONReadingMutableContainers
error: &error];
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"failure %#", [error localizedDescription]);
if (operation.response.statusCode == 500) {}
else if (operation.response.statusCode == 403) {}
}];

When you create the request operation you need to tell it which response status codes are acceptable (mean success). By default this is codes in the range 200 -> 299.
Setup before you start using the client:
AFHTTPRequestOperation.acceptableStatusCodes = ...;
[client postPath:
Docs are here.

Related

AFNetworking 3.0 - wrong authorization code

I'm using AFHTTPSessionManager to GET request with authorization headers;
In case of wrong user/password server according to postman is returning content type : text/html with:
<!DOCTYPE html>
<html>
<head>
<title>Apache Tomcat/8.0.21 - Error report</title>
<style type="text/css">H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}A {color : black;}A.name {color : black;}.line {height: 1px; background-color: #525D76; border: none;}</style>
</head>
<body>
<h1>HTTP Status 401 - Błąd podczas autentykacji</h1>
<div class="line"></div>
<p>
<b>type</b> Status report
</p>
<p>
<b>message</b>
<u>Błąd podczas autentykacji</u>
</p>
<p>
<b>description</b>
<u>This request requires HTTP authentication.</u>
</p>
<hr class="line">
<h3>Apache Tomcat/8.0.21</h3>
</body>
</html>
Unfortunately NSURLSessionDataTask returns
NSHTTPURLResponse *test = (NSHTTPURLResponse *)task.response;
NSLog (#"Status code, %i", test.statusCode);
returns Status code, 500
as well as NSError
NSString* errorResponse = [[NSString alloc] initWithData:(NSData *)error.userInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] encoding:NSUTF8StringEncoding];
NSLog(#"Error response: %#", errorResponse);
returns Error response: {"error":{"code":"UNKNOWN_ERROR","details":null,"description":"Server error","version":0}}
This is my get operation method.
- (void)getOperationForAction:(NSString *)action
parameters:(NSArray *)params
completion:(id (^)(id json, BOOL success))completion {
NSURL *url = [self apiUrlForAction:action params:params.mutableCopy];
AFHTTPSessionManager *manager = [self sessionManager];
[manager GET: url.absoluteString parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSLog(#"JSON: %#", responseObject);
if (completion) {
completion(responseObject, YES);
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSString *responseString = [[NSString alloc] initWithData:(NSData *)error.userInfo[NSLocalizedRecoverySuggestionErrorKey] encoding:NSUTF8StringEncoding];
if(responseString != nil && ![responseString isEqualToString: #""]) {
NSData *JSONData = [responseString dataUsingEncoding: NSUTF8StringEncoding];
id responseJSON = [NSJSONSerialization JSONObjectWithData:JSONData options: NSJSONReadingMutableContainers error:nil];
if(responseJSON != nil) {
}
}
NSHTTPURLResponse *test = (NSHTTPURLResponse *)task.response;
NSLog (#"Status code, %i", test.statusCode);
NSString* errorResponse = [[NSString alloc] initWithData:(NSData *)error.userInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] encoding:NSUTF8StringEncoding];
NSLog(#"Error response: %#", errorResponse);
ApiError *apiError = [[ApiError alloc] initWithString:errorResponse error:nil];
completion(apiError, NO);
}];
}
Request is handled correctly - the 401 issues appeared when I was intentionally using wrong auth login/password just to check the response errors. The problem is with incorrect status code as mentioned before.
#Edit
for
NSHTTPURLResponse *test = (NSHTTPURLResponse *)task.response;
NSLog (#"Status code, %i", test.statusCode);
NSLog (#"Error code, %i", error.code);
NSLog (#"Error domain, %#", error.domain);
Status code, 500
Error code, -1011
Error domain, com.alamofire.error.serialization.response

Error Code 220 - "Your credentials do not allow access to this resource" When tryig to get retweets

When i try to get https://api.twitter.com/1.1/statuses/retweets/21947795900469248.json with my authorized credentials (oauth), i'm getting:
{
"errors": [
{
"message": "Your credentials do not allow access to this resource",
"code": 220
}
]
}
error: Any other twit id's not working. Is there a problem with this endpoint? Because i was getting true response until yesterday. Something changed?
I experienced same issue with getting error code 220. Fix in my case was to prompt user to enter it's Twitter password again.
Check sample code below:
SLRequest *request = [SLRequest requestForServiceType:SLServiceTypeTwitter
requestMethod:SLRequestMethodPOST
URL:[NSURL URLWithString:#"https://api.twitter.com/1.1/statuses/update.json"]
parameters:#{#"status": tweetString}];
[request setAccount:account];
[request performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
if ([responseData isKindOfClass:[NSData class]]) {
NSError *jsonError = nil;
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:&jsonError];
if (json) {
NSArray *errors = json[#"errors"];
if (errors.count) {
NSUInteger errorCode = [json[#"errors"][0][#"code"] integerValue];
if (errorCode == 220) {
ACAccountStore *accountStore = [[ACAccountStore alloc] init];
[accountStore renewCredentialsForAccount:account completion:^(ACAccountCredentialRenewResult renewResult, NSError *error2) {
NSLog(#"Renew result: %ld, error: %#", (long)renewResult, error2);
if (renewResult == ACAccountCredentialRenewResultRenewed) {
[self __makeTweetWithAccounts:#[account] rating:rating review:review];
}
}];
}
}
}
}
NSLog(#"Twitter response data: %#", [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding]);
}];
Was getting the same error when I noticed I was using GET instead of POST. Changed it and it worked.
Set app permissions to Read, write, and direct messages
...and Regenerate Access Token and Token Secret.
It worked for me
I had similar problem with SLRequest class on iOS SDK7.1. Now to get retweets, or post retweet, i started to use deprecated class TWRequest. Just #import resource and use this method:
- (void)retweetMessageV2HavingId:(NSString*)messageId {
NSString *retweetString = [NSString stringWithFormat:#"https://api.twitter.com/1.1/statuses/retweet/%#.json", messageId];
NSURL *retweetURL = [NSURL URLWithString:retweetString];
TWRequest *request = [[TWRequest alloc] initWithURL:retweetURL parameters:nil requestMethod:TWRequestMethodPOST];
request.account = self.account;
[request performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
if (responseData)
{
NSError *parseError = nil;
id json = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:nil];
if (!json)
{
NSLog(#"Parse Error: %#", parseError);
}
else
{
NSLog(#"%#", json);
}
}
else
{
NSLog(#"Request Error: %#", [error localizedDescription]);
}
}]; }
I have generated access-tokens going to 'Keys and Access Tokens' tab in my current app page. Then, i have set 'Access Token' and 'Access Token Secret' for the access tokens for 'auth' obj that has permisson for the app to access in source code.

AFHTTPClient Expected status code in (200-299), got 409

I have strange issue with AFHTTPClient, I am sending POST request like
NSURL *u = [NSURL URLWithString:HTTP_SERVER];
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL: u];
[httpClient setParameterEncoding:AFJSONParameterEncoding];
[httpClient postPath:REGISTER
parameters:params
success:^(AFHTTPRequestOperation *operation, id JSON) {
int statusCode = [operation.response statusCode];
if(statusCode == 201){
[self performSegueWithIdentifier:#"register" sender:self];
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"[HTTPClient Error]: %#", error.localizedDescription);
}];
And server works fine ( in some cases server needs to answer me with code 409, API is made in that way), but I get error in XCode like Expected status code in (200-299), got 409
How to solve this problem ( my hands are tied, I cannot change API and error code) ?
Based on this:
You've got two options:
add status code 409 to the list of acceptable status codes, and receive it in the success block (bad)
deal with status code 409 in the failure block (good)
For the latter, if your [operation.response statusCode] is 409, you would use the responseData from AFURLConnectionOperation (superclass of AFHTTPRequestOperation, you would need to import its header for this to work).

AFHttpclient get json body in block but outer function returns null

I am trying to send post request on some url and in body to be only json data (trying to register new user sending json like
{
"username": "test",
"password": "test",
"email": "email#gmail.com"
}
I have function like
-(NSString*) sendPostOnUrl:(NSString*) url
withParameters:(NSDictionary*)params{
__block NSString* response = nil;
NSError *error;
NSURL *u = [NSURL URLWithString:url];
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL: u];
[httpClient postPath:REGISTER
parameters:params
success:^(AFHTTPRequestOperation *operation, id responseObject) {
response = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
NSLog(#"Request Successful, response '%#'", response);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"[HTTPClient Error]: %#", error.localizedDescription);
}];
return response;
}
where params are NSDictionary with keys username, password and email and values for those keys.
Problem is when I send I always in return get null in response (the latest line) but in NSLog I get json response.. I am very new to ios, and it looks to me that I need to sync on some way block with return from function but don't know how, can anybody give me a clue what am I doing wrong ? (params contains all those keys when I try to debug, url is ok, REGISTER is NSString constant)
Blocks are asynchronous - the problem here is that "response = [[NSString alloc] initWithData..." is within the block which gets executed after you've exited the method. A better approach is to not do this in a method, instead place this code where you were calling sendPostOnUrl:withParameters: and do whatever it is you need to do within the success block. So instead of:
self.something = [self sendPostOnUrl:url withParameters:#{"username":"test" etc}];
you do this:
NSError *error;
NSURL *u = [NSURL URLWithString:url];
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL: u];
__weak YourClassName *me = self;
[httpClient postPath:REGISTER
parameters:params
success:^(AFHTTPRequestOperation *operation, id responseObject) {
me.something = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
NSLog(#"Request Successful, response '%#'", response);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"[HTTPClient Error]: %#", error.localizedDescription);
}];
Also, take note of "__weak YourClassName *me = self", you cannot reference self within a block because it will cause a retain cycle.

AFNetworking: Can't get the response string from AFHTTPRequestOperation

Anyone?): I'm having a problem that has made me scratch my head for the last 2 hours, and it most likely a very simple stupid thing I'm missing. I Keep getting a building error when I Call the response string from the operation # AFNetworking... Like there is NO SUCH PROPERTY....
Please Take a look at my code and Explain me what did I Mess up This time :p.. THanks :)
NSDictionary* paramDict = [NSDictionary dictionaryWithObjectsAndKeys:WebServicemd5Value, WebSermd5Variable, nil]
;
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:webServiceURL]];
[httpClient defaultValueForHeader:#"Accept"];
[httpClient postPath:#"method" parameters:paramDict success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Response data: %#", responseObject);
NSLog(#"Reponse String: %#", operation);
// Printing operation will show me the operation Dictionary, including the reponse field, // but when I Directly call operation.response, the Compiler won't Build, stating that // "Property not found for AFHTTPRequestOperation".... WEIRDEST THING EVER, right?
NSString* responseString = [NSString stringWithUTF8String:[responseObject bytes]];
//.. Rest o f my Code....
}failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error retrieving data: %#", error);
}];
Hernan, if you expect an NSDictionary from a JSON response you should consider using AFJSONRequestOperation, because you get a JSON dictionary in your success callback. Anyway, if you want to get a dictionary from your responseObject, try to use the following code:
NSError *error = nil;
NSDictionary *JSON = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingAllowFragments error:&error];
if (error) {
NSLog(#"Error serializing %#", error);
}
NSLog(#"Dictionary %#", JSON);
I believe the response string is inside the "operation" object, so something like:
...
}failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error retrieving data: %#", operation.responseString);
}];
While attempting to retrieve content from meetup.com api using AFNetworking (kudos to Mattt T. for a great framework, btw), ran into the same error - "The operation couldn't be completed. (Cocoa error 3840)". Realized that the issue I was having was with the response data containing a Swedish character 'Ø', resulting in the parsing error. The solution was to include the header 'Accept-Charset: utf-8' in the initialization of the AFNetworking client. Fixed!
- (id)initWithBaseURL:(NSURL *)url {
self = [super initWithBaseURL:url];
if (!self) {
return nil;
}
[self registerHTTPOperationClass:[AFJSONRequestOperation class]];
// Accept HTTP Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
[self setDefaultHeader:#"Accept" value:#"application/json"];
[self setDefaultHeader:#"Accept-Charset" value:#"utf-8"];
return self;
}

Resources