iOS: Comment puis-je recevoir le protocole HTTP 401 au lieu de -1012 NSURLErrorUserCancelledAuthentication

J'ai un problème similaire à celui décrit dans le lien ci-dessous.

NSHTTPURLResponse statusCode returnne zéro lorsqu'il devrait être 401

J'utilise [NSURLConnection sendSynchronousRequest:returningResponse:error:] pour get des données d'un server.

Lorsque NSURLConnection reçoit le code HTTP 401, il ne renvoie rien mais un object d'erreur avec le code -1012 partir de NSURLErrorDomain. -1012 correspond à NSURLErrorUserCancelledAuthentication . Comme je dois parsingr l'en-tête HTTP, j'ai besoin d'get l'erreur d'origine et non ce que NSURLConnection en a fait.

Y at-il un moyen de recevoir le package original 401 http?

    Oui. Arrêtez d'utiliser l'API synchrone. Si vous utilisez l'API asynchronous déléguée, vous avez plus de contrôle sur la connection. Avec cette API, sauf dans les cas où une erreur est rencontrée avant la réception de l'en-tête HTTP, vous recevrez toujours -connection:didReceiveResponse: qui vous donne access aux champs d'en-tête HTTP (encapsulés dans un object NSURLResponse ). Vous pouvez également implémenter l'authentification à l'aide des methods de délégué appropriées si vous le souhaitez.

    Solution de contournement:

     [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue new] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { NSHTTPURLResponse *aResponse = (NSHTTPURLResponse *)response; int statusCodeResponse = aResponse.statusCode; NSSsortingng *strError = [NSSsortingng ssortingngWithFormat:@"%@", [connectionError description]]; if ([strError rangeOfSsortingng:@"Code=-1012"].location != NSNotFound) { statusCodeResponse = 401; } 

    Ce n'est pas la meilleure solution, mais ça marche!

    Je suis surpris de la réponse "recommandée" à ce sujet.

    Bien, je suis sûr que l'utilisation des methods de la version async est meilleure, mais cela n'explique toujours pas pourquoi la fonction sendSynchronousRequest vous permet de passer une variable pour returnner le code de réponse, mais dans certains cas, elle renvoie simplement nil .

    Cela fait 4 ans que ce problème a été signalé, j'utilise XCode 6.2 avec iOS 8.2, et ce bug ancien est toujours présent.

    Mes services Web renvoient délibérément une erreur 401 lorsque le nom d'user et le mot de passe d'un user ne sont pas corrects.

    Quand mon application iPhone appelle ce service (avec les fausses informations d'identification) …

     NSHTTPURLResponse *response = nil; NSData *data = [ NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error ]; 

    .. response est returnnée comme nulle (donc je ne peux pas tester la réponse HTTP 401), error reçoit un message -1012 enveloppé comme ceci:

      Error Domain=NSURLErrorDomain Code=-1012 "The operation couldn't be completed. (NSURLErrorDomain error -1012.)" UserInfo=0x174869940 {NSErrorFailingURLSsortingngKey=https://mywebservice.com/Service1.svc/getGroupInfo/6079, NSUnderlyingError=0x174e46030 "The operation couldn't be completed. (kCFErrorDomainCFNetwork error -1012.)", NSErrorFailingURLKey=https://mywebservice.com/Service1.svc/getGroupInfo/6079} 

    et la fonction sendSynchronousRequest renvoie une longue string XML contenant … bien … ceci

     <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Request Error</title> <style>BODY { color: #000000; background-color: white; font-family: Verdana; margin-left: 0px; margin-top: 0px; } #content { margin-left: 30px; font-size: .70em; padding-bottom: 2em; } A:link { color: #336699; font-weight: bold; text-decoration: underline; } A:visited { color: #6699cc; font-weight: bold; text-decoration: underline; } A:active { color: #336699; font-weight: bold; text-decoration: underline; } .heading1 { background-color: #003366; border-bottom: #336699 6px solid; color: #ffffff; font-family: Tahoma; font-size: 26px; font-weight: normal;margin: 0em 0em 10px -20px; padding-bottom: 8px; padding-left: 30px;padding-top: 16px;} pre { font-size:small; background-color: #e5e5cc; padding: 5px; font-family: Courier New; margin-top: 0px; border: 1px #f0f0e0 solid; white-space: pre-wrap; white-space: -pre-wrap; word-wrap: break-word; } table { border-collapse: collapse; border-spacing: 0px; font-family: Verdana;} table th { border-right: 2px white solid; border-bottom: 2px white solid; font-weight: bold; background-color: #cecf9c;} table td { border-right: 2px white solid; border-bottom: 2px white solid; background-color: #e5e5cc;}</style> </head> <body> <div id="content"> <p class="heading1">Request Error</p> <p>The server encountered an error processing the request. The exception message is 'Access is denied.'. See server logs for more details. The exception stack trace is: </p> <p> at System.ServiceModel.Dispatcher.AuthorizationBehavior.Authorize(MessageRpc&amp; rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc&amp; rpc) at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)</p> </div> </body> </html> 

    Allez Apple, réparez vos bugs …

    C'est vraiment simple. Maintenant, il est vrai que la requête asynchronous est en fait une très bonne aide. Mais vous devez garder à l'esprit que c'est juste une aide. Http est juste un protocole pour le networking et par conséquent, il ne doit pas interagir avec l'user. En d'autres termes, les deux cas sont en réalité identiques.

    Si vous ne voulez pas utiliser l'assistant asynch que je vous suggère de montrer à l'user une boîte de dialog de connection et de répéter votre request jusqu'à ce que l'user appuie sur annuler.

    [modifier]

    juste pour info, personnellement je préfère curl. Fonctionne comme un charme presque partout;)

    Je faisais face à la question ne recevant pas le code d'erreur 401 non autorisé (recevait la réponse nulle aussi la méthode didReceiveResponse n'a pas été appelée) au lieu de recevoir l'erreur -999 annulée. L'erreur que je faisais dans mon code est: Dans didReceiveChallenge: méthode de délégué,

     if (challenge.previousFailureCount == 0) { //handle certificatee trust completionHandler (NSURLSessionAuthChallengeUseCredential, newCredential); } else { completionHandler (NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil); } 

    Le NSURLSessionAuthChallengeCancelAuthenticationChallenge entraînait l'erreur -999 et aucune réponse 401 n'a été obtenue. Au lieu de cela, j'ai utilisé completionHandler (NSURLSessionAuthChallengePerformDefaultHandling, nil); Je recevais la réponse 401 dans didReceiveResponse: méthode de délégué comme prévu.

    Note de la documentation iOS https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/URLLoadingSystem/NSURLSessionConcepts/NSURLSessionConcepts.html , Si nous annulons l'URL, il sera signalé comme annulé, mais pas comme erreur 401 en réponse.

     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 classs.