NSURLConnection retry on 401 status

丶灬走出姿态 提交于 2019-12-11 02:33:45

问题


I'm communicating with a server that validates a password and returns a 401 error on invalid password, together with a json body specifying the number of failed attempts. That number is incremented by the server on each failed validation.

The problem I'm facing is that when NSURLConnection gets a 401 response, it kicks an authentication mechanism that involves these delegate methods:

connection:canAuthenticateAgainstProtectionSpace:

connection:didReceiveAuthenticationChallenge:

If I return NO in the canAuthenticate method, a new identical request will be made. This will result in the server incrementing the failed attempts a second time (which is obviously not desired) and I'll get a 401 response (connection:didReceiveResponse:)

If I return YES in the canAuthenticate method, then the didReceiveAuthenticationChallenge method is called. If I want to stop the second request, I can call [challenge.sender cancelAuthenticationChallenge:challenge]. But if I do that, I won't get a 401 response, but an error.

I've found no way to capture the first 401 response. Is there any way to do that?


回答1:


1) For plain vanilla SSL without client certificate you don't need to implement these 2 methods

2) If you still want to, you should check for the HTTP response code in the [challenge failureResponse] object:

- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
    NSURLCredential *urlCredential = [challenge proposedCredential];
    NSURLResponse *response = [challenge failureResponse];
    int httpStatusCode = -1;
    if(response != nil) {
        NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
        httpStatusCode = [httpResponse statusCode];
    }    
    if(urlCredential != nil || httpStatusCode == 401) {
        //wrong username or more precisely password, call this to create 401 error
        [[challenge sender] cancelAuthenticationChallenge:challenge];
    }
    else {
        //go ahead, load SSL client certificate or do other things to proceed
    }    
}

- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
{       

 return YES;
}



回答2:


If all else fails, try this: a wonderful library available, called AFNetworking, which is very easy to implement.

It uses blocks, which greatly simply communication of data between classes (does away with delegates), and is asynchronous.

Example usage is below:

AFHTTPClient *client = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:"www.yourwebsite.com/api"]];

NSDictionary *params = @{
    @"position": [NSString stringWithFormat:@"%g", position]
};

[client postPath:@"/api" parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {

} failure:^(AFHTTPRequestOperation *operation, NSError *error) {

}];

As simple as that! Result is available directly within the class that calls the HTTP Post or Get method.

It even includes image and JSON requests, JSON deserialization, file download with progress callback, and so much more.



来源:https://stackoverflow.com/questions/13944527/nsurlconnection-retry-on-401-status

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