iOS: Comment puis-je recevoir HTTP 401 au lieu de -1012 Nslerrorusercancelledauthentication

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

NSHTTPURLResponse statusCode retourne zéro alors qu'il devrait être 401

j'utilise [NSURLConnection sendSynchronousRequest:returningResponse:error:] pour obtenir des données à partir d'un serveur.

quand Nslurlconnection reçoit le code HTTP 401, Il ne renvoie qu'un objet d'erreur avec le code -1012 de la Nslerrordomaine. -1012 correspond à NSURLErrorUserCancelledAuthentication . Puisque je dois analyser L'en-tête HTTP, je dois récupérer l'erreur originale et non ce que Nslconnection en a fait.

y a-t-il un moyen de recevoir le paquet http 401 original?

32
demandé sur Community 2010-10-12 11:47:31

5 réponses

Oui. Arrêtez d'utiliser l'API synchrone. Si vous utilisez l'API asynchrone basée sur delegate, vous avez beaucoup plus de contrôle sur la connexion. Avec cette API, sauf dans les cas où une erreur se produit avant la réception de L'en-tête HTTP, vous obtiendrez toujours receive -connection:didReceiveResponse: , ce qui vous donne accès aux champs D'en-tête HTTP (encapsulés dans un objet NSURLResponse ). Vous pouvez également mettre en place l'authentification selon le délégué méthodes si vous êtes si enclin.

19
répondu Kevin Ballard 2011-01-13 20:22:43

solution de contournement:

[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue new] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {

NSHTTPURLResponse *aResponse = (NSHTTPURLResponse *)response;
int statusCodeResponse = aResponse.statusCode;

NSString *strError = [NSString stringWithFormat:@"%@", [connectionError description]];
if ([strError rangeOfString:@"Code=-1012"].location != NSNotFound) {
    statusCodeResponse = 401;
   }

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

18
répondu Marcelo dos Santos 2014-04-28 19:01:12

je suis surpris de la réponse" recommandé " à ce fil.

bien, je suis sûr que l'utilisation des méthodes de version asynchrone sont mieux, mais il n'explique toujours pas pourquoi la fonction sendSynchronousRequest ne vous permet pas de passer dans une variable pour retourner le code de réponse, mais dans certaines circonstances, il retourne juste nil .

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

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

quand mon application iPhone appelle ce service (avec les mauvaises références)...

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

.. response est retourné comme nul (donc I can't test pour 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 {NSErrorFailingURLStringKey=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 chaîne XML contenant... bien... ce ...

<?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épare tes bugs...

11
répondu Mike Gledhill 2015-03-30 08:43:12

Ses effectivement arrêter simple. Maintenant il est vrai que la demande asynchrone est en fait une assez bonne aide. Mais vous devez garder à l'esprit que c'est juste une aide. Http n'est qu'un protocole de mise en réseau et ne doit donc pas interagir avec l'utilisateur. En d'autres termes, les deux cas sont en fait identiques.

si vous ne voulez pas utiliser le helper asynch que je vous suggère de montrer à l'utilisateur un dialogue de connexion et de répéter votre demande jusqu'à ce que l'utilisateur appuie sur Annuler.

[modifier]

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

0
répondu user1820381 2012-11-30 08:41:43

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

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

le Nslsurlsessionauthchallengecancelauthenticationchall a entraîné l'erreur -999 et il n'y a pas eu de réponse 401. À la place quand j'ai utilisé completionHandler (NSURLSessionAuthChallengePerformdefaulthandling, nil); j'ai été reçu réponse 401 dans didReceiveResponse: méthode du délégué comme prévu.

Note de la documentation de iOS https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/URLLoadingSystem/NSURLSessionConcepts/NSURLSessionConcepts.html , si nous annulons l'urlsession alors il sera rapporté comme annulé, mais pas comme erreur 401 dans la 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 classes.
0
répondu Lakshmi S 2017-05-10 16:44:35