NSURLConnection returning error instead of response for 401

你说的曾经没有我的故事 提交于 2021-02-07 03:39:09

问题


I have a web API that, for a specific request returns status code 200 if everything went ok, and 401 if the user is not logged in based on an Authorization token. Everything works fine if the response status is 200, but doesn't seem to work properly if the response status is 401, returning a connection error with code -1012, while the response is nil.

So, the following code:

[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
    NSLog(@"%@", response);
    NSLog(@"%@", connectionError);

    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
    int statusCode = (int)[httpResponse statusCode];
    NSLog(@"response status code: %d", statusCode);

will display

2015-04-01 15:58:18.511 MyProject[3618:694604] <NSHTTPURLResponse: 0x155facc0> { URL: *SOME_URL* } { status code: 200, headers {
    "Access-Control-Allow-Headers" = "Content-Type, Accept, X-Requested-With";
    "Access-Control-Allow-Methods" = "POST, GET, PUT, UPDATE, OPTIONS";
    "Access-Control-Allow-Origin" = "*";
    Connection = "keep-alive";
    "Content-Type" = "application/json";
    Date = "Wed, 01 Apr 2015 12:58:14 GMT";
    Server = "Wildfly 8";
    "Transfer-Encoding" = Identity;
    "X-Powered-By" = "Undertow 1";
} }
2015-04-01 15:58:18.513 MyProject[3618:694604] (null)
2015-04-01 15:58:18.513 MyProject[3618:694604] response status code: 200

if the response status is 200, while if the status code is 401, I will get:

2015-04-01 16:05:55.988 MyProject[3633:695836] (null)
2015-04-01 16:05:55.992 MyProject[3633:695836] Error Domain=NSURLErrorDomain Code=-1012 "The operation couldn’t be completed. (NSURLErrorDomain error -1012.)" UserInfo=0x146137c0 {NSErrorFailingURLKey=*SOME_URL*, NSErrorFailingURLStringKey=*SOME_URL*, NSUnderlyingError=0x1459e6d0 "The operation couldn’t be completed. (kCFErrorDomainCFNetwork error -1012.)"}
2015-04-01 16:05:55.992 MyProject[3633:695836] response status code: 0

If I do the same request using Postman or an Android device, I will get status code 401 with the following headers(copied from Postman):

Connection → keep-alive
Content-Length → 30
Content-Type → application/json
Date → Wed, 01 Apr 2015 13:07:34 GMT
Server → Wildfly 8
X-Powered-By → Undertow 1

Is there any fix or maybe a library that could give me some accurate response status? I searched a bit about the -1012 error, but couldn't find much and I don't really want to base on that.

Edit: after a bit of research I found the following statement on Appl's documentation: "If authentication is required in order to download the request, the required credentials must be specified as part of the URL. If authentication fails, or credentials are missing, the connection will attempt to continue without credentials."

But then how can I know if this error will be after a 401 status? Can it appear after another type of request?


回答1:


In order to get the 401 status code, I think you'll need to implement protocol NSURLConnectionDelegate and then connection:didReceiveAuthenticationChallenge:.

So, you'll also need to pass the delegate, maybe using [NSURLConnection connectionWithRequest:request delegate:self].

And, if you aren't trying to implement the authentication challenge, I would rather always return the 200 status code, but with different json content.

Hope it can help.




回答2:


to check the 401 error, you can do this:

if (error != nil && error.code == NSURLErrorUserCancelledAuthentication) {
    // do something for 401 error
}

hope this help




回答3:


I have a web API that, for a specific request returns status code 200 if everything went ok, and 401 if the user is not logged in based on an Authorization token. Everything works fine if the response status is 200, but doesn't seem to work properly if the response status is 401, returning a connection error with code -1012, while the response is nil.

I've run exactly into the same problem, REST API call returns 401 in Android and Postman, but status code 0 in iOS with a connection error with code -1012.

You can find more information about this problem in this SO post.

Seems to be an iOS bug (or at least very strange approach) happening both with async and sync requests.

I'm posting this just in case this might be useful for others bumping into the same issue. What I did in the code to manage the 401 status, right after the request, is to call a method that checks each managed http status code.

The method receives (NSError **)error and [(NSHTTPURLResponse *)response statusCode].

This is the 401 part - uses the error details stored inside userInfo structure.

// Auth failed or token problems
if (statusCode == 0 && [error userInfo] != nil) {

    // Get error detailed informations
    NSDictionary *userInfo = [error userInfo];
    NSString *errorString = [[userInfo objectForKey:NSUnderlyingErrorKey] localizedDescription];

    // If error message is of type authFailed or returns iOS code -1012 meaning auth failed
    if ([errorString containsString:@"kCFErrorDomainCFNetwork"] || [errorString containsString:@"-1012"]) {
        NSLog(@"%@ - ConnectionError - Code 401 - Cause: authentication failed, token is invalid or expired", type);
    } else {
        NSLog(@"%@ - ConnectionError - Cause: generic auth error", type);
    }

    // Alert user that auth failed
    ...
}

The other way is to check directly for this error code (-1012) as suggested by @ThuanDINH above. (edited the answer for objective c).

My code can be changed into:

// Auth failed - token problems
if (statusCode == 0 && [error code] == NSURLErrorUserCancelledAuthentication) {

    // If error code is UserCanceledAuthentication
    MPLog(MPLogLevelInfo, @"%@ - ConnectionError - Cause: authentication failed, token is invalid or expired", type);

    // Alert user that auth failed
    ...
}

But in this way you will not handle all other errors (you need to switch on each NSURLError code).

Here you can find the SO question with the list of all the NSURLError codes.




回答4:


Based on Apple documentation https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/URLLoadingSystem/NSURLSessionConcepts/NSURLSessionConcepts.html,

Note: NSURLSession does not report server errors through the error parameter. The only errors your delegate receives through the error parameter are client-side errors, such as being unable to resolve the hostname or connect to the host. The error codes are described in URL Loading System Error Codes.
Server-side errors are reported through the HTTP status code in the NSHTTPURLResponse object. For more information, read the documentation for the NSHTTPURLResponse and NSURLResponse classes.

We need to make sure that we do not cancel the session in our code. For example, I was calling NSURLSessionAuthChallengeCancelAuthenticationChallenge in didReceiveChallenge delegate method, when previousFailureCount > 1. This was suppressing 401 response and also call to didReceiveResponse.

When I changed above value to NSURLSessionAuthChallengePerformDefaultHandling, I am receiving 401 Unauthorized response in didReceiveResponse delegate method and works as expected.



来源:https://stackoverflow.com/questions/29391892/nsurlconnection-returning-error-instead-of-response-for-401

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!