iOS: ¿Cómo puedo recibir HTTP 401 en lugar de -1012 NSURLErrorUserCancelledAuthentication


Tengo un problema similar al descrito en el siguiente enlace.

NSHTTPURLResponse statusCode devuelve cero cuando debería ser 401

Uso [NSURLConnection sendSynchronousRequest:returningResponse:error:] para obtener datos de un servidor.

Cuando NSURLConnection recibe el código HTTP 401, no devuelve nada más que un objeto de error con el código -1012 del dominio Nsurlerrord. -1012 corresponde a NSURLErrorUserCancelledAuthentication. Dado que tengo que analizar el encabezado HTTP, necesito obtener el error original y no lo que hizo NSURLConnection fuera de ella.

¿Hay alguna forma de recibir el paquete http 401 original?

Author: Community, 2010-10-12

5 answers

Sí. Deje de usar la API síncrona. Si utiliza la API basada en delegados asíncronos, tendrá mucho más control sobre la conexión. Con esta API, excepto en los casos en que se encuentre un error antes de recibir el encabezado HTTP, siempre recibirá -connection:didReceiveResponse:, lo que le da acceso a los campos de encabezado HTTP (encapsulados en un objeto NSURLResponse). También puede implementar la autenticación utilizando los métodos de delegado relevantes si así lo desea.

 19
Author: Kevin Ballard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-01-13 20:22:43

Solución:

[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;
   }

No Es la mejor solución, pero funciona!

 18
Author: Marcelo dos Santos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-28 19:01:12

Me sorprende la respuesta "recomendada" a este hilo.

Bien, estoy seguro de que usar los métodos de versión asincrónica son mejores, pero todavía no explica por qué la función sendSynchronousRequestle permite pasar una variable para devolver el código de respuesta, pero en algunas circunstancias, solo devuelve nil.

It' 4 años desde que se informó de este problema, estoy usando XCode 6.2 con iOS 8.2, y este antiguo error todavía está presente.

Mis servicios web deliberadamente devuelve un error 401 cuando el nombre de usuario y la contraseña de un usuario no son correctos.

Cuando la aplicación de mi iPhone llama a este servicio (con las credenciales incorrectas)...

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

..{[4] } se devuelve como nil (por lo que no puedo probar la respuesta HTTP 401), error recibe un mensaje -1012 envuelto así:

    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}

Y la función sendSynchronousRequest devuelve una larga cadena XML que contiene... bien... esto ...

<?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>

Vamos Apple, arregla tus errores...

 11
Author: Mike Gledhill,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-03-30 08:43:12

En realidad es salir simple. Ahora es cierto que la solicitud async es en realidad un ayudante bastante bueno. Pero hay que tener en cuenta que es solo un ayudante. Http es solo un protocolo para redes y por lo tanto no debe interactuar con el usuario. En otras palabras, ambos casos son en realidad uno y el mismo.

Si no desea utilizar el ayudante asynch, le sugiero que muestre al usuario un diálogo de inicio de sesión y repita su solicitud hasta que el usuario presione cancelar.

[editar]

Solo para información, personalmente prefiero rizo. Funciona como un encanto en casi todas partes;)

 0
Author: user1820381,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-30 08:41:43

Me enfrentaba al problema de no recibir el código de error no autorizado 401 (estaba recibiendo respuesta nil también el método didReceiveResponse no estaba siendo llamado) en lugar de recibir el error cancelado -999. El error que estaba haciendo en mi código es: En didReceiveChallenge: método delegado,

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

El desafío Nsurlsessionauthchallengecancelauthentication resultó en el error -999 y no se obtuvo respuesta 401. En lugar de eso, cuando usé completeHandler (NSURLSessionAuthChallengePerformDefaultHandling, nil); Estaba recibiendo 401 respuesta en didReceiveResponse: delegate method as expected.

Nota de la documentación de iOS https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/URLLoadingSystem/NSURLSessionConcepts/NSURLSessionConcepts.html, Si cancelamos la urlsession, se informará como cancelada, pero no como error 401 en respuesta.

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
Author: Lakshmi S,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-10 16:44:35