How to get status code in AFNetworking
Asked Answered
E

9

17

I have a method, for authorizing user. I need Basic authorization.

    NSString *url = [NSString stringWithFormat:@"%@/rest/api/person/auth", host];
    AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
    [manager setRequestSerializer:[AFHTTPRequestSerializer serializer]];
    [manager.requestSerializer setAuthorizationHeaderFieldWithUsername:_loginField.text password:_passwordField.text];
    [manager setResponseSerializer:[AFJSONResponseSerializer serializer]];
    [manager GET:url parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
        [self parseResponseForUser:responseObject];
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        NSLog(@"Error %@ ",error);
    }];

The main problem here is determining error type. I may have error for authorization and error for network connection problem (host is not reachable). When login and password don't match criteria, failure block runs. For example, If I put wrong password and login I take this error message.:

Error Domain=NSCocoaErrorDomain Code=3840 "The operation couldn’t be completed. (Cocoa error 3840.)" (JSON text did not start with array or object and option to allow fragments not set.)

How should i catch error types?

Estevez answered 13/12, 2013 at 12:9 Comment(2)
Can you post the JSON you're trying to get please ?Ansilme
I've updated my question, i've posted response that i amtrying to getEstevez
E
31

Finally found answer, may be it will be helpful for someone. I just needed to use:

NSInteger statusCode = operation.response.statusCode;

And i can catch it like:

    [manager GET:url parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
        NSLog(@"response:%@", responseObject);
        [self parseResponseForUser:responseObject];
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        NSInteger statusCode = operation.response.statusCode;
        if(statusCode == 401) {
        } else if (statusCode == 404) {
        }
    }];
Estevez answered 14/12, 2013 at 3:23 Comment(2)
NSInteger should be used going forward as we move to 64 bit arch.Khufu
This is not valid for AFURLSessionManager which uses tasks, not AFHTTPRequestOperationAggregate
M
21

In AFNetworking 3.0+ and in the case of an error, you can access the status code in the failure block's error.userInfo object:

failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {

    NSHTTPURLResponse *response = error.userInfo[AFNetworkingOperationFailingURLResponseErrorKey];

    NSInteger statusCode = response.statusCode;

    // Do something with the status code
}];
Messner answered 15/12, 2015 at 2:45 Comment(0)
S
7

you can give a try to get code from error and then show messages accordingly.

failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSInteger statusCode = error.code;
    if(statusCode == -1001) {
      // request timed out
    } else if (statusCode == -1009 || statusCode || -1004) {
      // no internet connectivity
    }
}];

similarly you can check for other code.

Sociability answered 24/6, 2014 at 5:17 Comment(0)
D
6

Here's how I do it.

[self.httpClient GET:@"someAPI"
          parameters:parametersDictionary
             success:^(NSURLSessionDataTask *task, id responseObject) {
             } failure:^(NSURLSessionDataTask *task, NSError *error) {
               NSHTTPURLResponse *response = (NSHTTPURLResponse *)task.response;
               NSInteger statusCode = [response statusCode];
               switch (statusCode) {
                 case 404:
                   break;
                 default:
                   break;
               }
             }];
Defilade answered 1/12, 2015 at 7:52 Comment(0)
O
1

Improved response of alok srivastava by using NSURLError enum:

failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSInteger statusCode = error.code;
if(statusCode == NSURLErrorTimedOut) {
  // request timed out
} else if (statusCode == NSURLErrorNotConnectedToInternet || statusCode || NSURLErrorCannotConnectToHost) {
  // no internet connectivity
}}];
Obsequious answered 2/5, 2016 at 9:0 Comment(0)
S
1

Here is how to do it in Swift

((NSURLSessionDataTask, NSError) -> Void) = { (sessionDataTask :NSURLSessionDataTask, responseError : NSError) -> Void in
    let response  = sessionDataTask.response as! NSHTTPURLResponse
    switch (statusCode) {
      case 404:
        // do stuff
      case 401:
        // do stuff
      default:
        break;
    }
}
Spleenful answered 1/7, 2016 at 7:2 Comment(0)
M
0

It looks like your server might respond with HTML, or it might respond with JSON. But when you type:

[manager setResponseSerializer:[AFJSONResponseSerializer serializer]];

You're telling AFNetworking to expect JSON.

Instead, try telling it to handle a regular HTTP response if it's not JSON:

NSArray *serializers = @[[AFJSONResponseSerializer serializer], [AFHTTPResponseSerializer serializer]];
AFCompoundSerializer *compoundResponseSerializer = [AFCompoundSerializer compoundSerializerWithResponseSerializers:serializers];
[manager setResponseSerializer:compoundResponseSerializer];

Now, if the JSON serializer fails, the request will be passed to the AFHTTPResponseSerializer, which should call your failure block with the appropriate HTTP error code instead of the JSON parsing error.

Incidentally, AFHTTPResponseSerializer is subclass-able, so feel free to take a look at that option if you want more specific behavior.

Melinite answered 13/12, 2013 at 15:31 Comment(1)
Thanks, AAron. Today I tried this solution, but i get stucked, from where I should import AFCompoundSerializer. Reading documentation of AFNetworking I found method for getting statusCode.Estevez
J
0

It happens frequently, that servers may send a response in a different content type than requested IF they are sending an error.

For example when sending a request with JSON as Content-Type and expecting a JSON response from the server, one would specify the following request headers:

Content-Type: application/json
Accept: application/json

When the request fails due to an authentication error, the server may send you a status code of 401 (Unauthorized) plus an optional response which contains relevant diagnostic information.

Strictly, web servers should respect the Accept header, but unfortunately, some don't and will send a "standard" error response in text/html for example. The details should be specified in the API, though.

Your implementation should handle that case gracefully. That is, your response handler must encode (or parse) the response data according the Content-Type of the response, say text/html or ignore it if suitable. More precisely, you always should query the HTTP status code AND the content type and then make an informed decision how you want to treat the response.

See Aron Brager's answer how to solve that issue with AFN.

Justiciar answered 13/12, 2013 at 16:15 Comment(0)
U
-1

your Json must be:

{
    "access" : "1",
    "admin" : "0",
    "code" : "constantine2",

    ...

    "positions" : [
                {
            "departmentID" : "992c93ee-2fa7-4e53-be5f-4e32a45ba5e6",
            "departmentName" : "Dev-C++ resources page (libraries, sources, updates...)",
            ....
        }
    ],
    "userid" : "3b660c13-b856-41fa-a386-814a7b43bacc"
}
Urien answered 13/12, 2013 at 14:8 Comment(4)
I am sure that JSON is right, because I can parse the data, when I enter correct login and password. The problem occurs when I enter incorrect login or password. The server side sends me html response (error 401, user is not authorized) instead of json. I would like to catch errors, so that if error type is equal to 401, I want to show an alertview like "User is not authorized", if error type equals 404, i want to show user "incorrect url message". Any help would be appreciated.Estevez
Instead putting -1 write your question correctly. And the answer is: first of [self parseResponseForUser:responseObject]; check your responceObject content and type, and if(is 404 ?) {alert} else {[self parseResponseForUser:responseObject];}Urien
I didn't put -1 to you. I have only 13 reputation, I can't even vote. I can only select best answer nowEstevez
My apologize. Someone else - very smartUrien

© 2022 - 2024 — McMap. All rights reserved.