NSURLConnection повторяется при статусе 401

Я связываюсь с сервером, который проверяет пароль и возвращает ошибку 401 при недопустимом пароле, вместе с телом json, указывающим количество неудачных попыток. Это число увеличивается сервером при каждой неудачной проверке.

Проблема, с которой я столкнулся, заключается в том, что когда NSURLConnection получает ответ 401, он запускает механизм аутентификации, который включает следующие методы делегата:

connection: canAuthenticateAgainstProtectionSpace:

connection: didReceiveAuthenticationChallenge:

Если я верну NO в методе canAuthenticate, будет сделан новый идентичный запрос. Это приведет к тому, что сервер увеличит количество неудачных попыток во второй раз (что, очевидно, нежелательно), и я получу ответ 401 (connection: didReceiveResponse:)

Если я возвращаю YES в методе canAuthenticate, то вызывается метод didReceiveAuthenticationChallenge. Если я хочу остановить второй запрос, я могу вызвать [challenge.sender cancelAuthenticationChallenge: challenge]. Но если я это сделаю, то получу не ответ 401, а ошибку.

Я не нашел способа получить первый ответ 401. Есть ли способ сделать это?


person Mariano Ruggiero    schedule 19.12.2012    source источник
comment
Мариано, ты когда-нибудь придумал, как это исправить? Прямо сейчас у меня такая же проблема :(   -  person Dirk de Kok    schedule 27.08.2013


Ответы (2)


1) Для простого ванильного SSL без сертификата клиента вам не нужно реализовывать эти 2 метода

2) Если вы все еще хотите, вы должны проверить код ответа HTTP в объекте [challenge failureResponse]:

- (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;
}
person Dirk de Kok    schedule 27.08.2013

Если ничего не помогает, попробуйте следующее: доступна замечательная библиотека под названием AFNetworking, которую очень легко реализовать.

Он использует блоки, которые значительно упрощают обмен данными между классами (избавляются от делегатов) и являются асинхронными.

Пример использования приведен ниже:

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) {

}];

Так просто! Результат доступен непосредственно в классе, который вызывает метод HTTP Post или Get.

Он даже включает запросы изображений и JSON, десериализацию JSON, загрузку файла с обратным вызовом выполнения и многое другое.

person bibo bode    schedule 19.12.2012
comment
Да, AFNetworking - отличная библиотека, но у меня много кода, построенного на NSURLConnection. - person Mariano Ruggiero; 19.12.2012
comment
Вам не нужно заменять этот старый код. Я знаю, что когда я впервые начал использовать его на своем рабочем месте, все наше приложение было разработано на основе NSURLConnection. Но мы постепенно перешли к тому моменту, когда все теперь использует AFNetworking. - person bibo bode; 20.12.2012