iOS:我如何接收HTTP 401而不是-1012 NSURLErrorUserCancelledAuthentication

我有一个类似于下面的链接中描述的问题。

NSHTTPURLResponse statusCode返回零时,它应该是401

我使用[NSURLConnection sendSynchronousRequest:returningResponse:error:]从服务器获取数据。

当NSURLConnection接收到HTTP代码401时,它不会返回任何东西,而是返回-1012代码为-1012的错误对象。 -1012对应于NSURLErrorUserCancelledAuthentication 。 由于我必须parsingHTTP头,我需要得到原来的错误,而不是NSURLConnection做出来的。

有没有办法接收原始的401 HTTP数据包?

是。 停止使用同步API。 如果您使用基于asynchronous委托的API,那么您对连接有更多的控制。 使用此API,除了在收到HTTP头之前遇到错误的情况,您将始终会收到-connection:didReceiveResponse: NSURLResponse它允许您访问HTTP头字段(封装在NSURLResponse对象中)。 如果您倾向于使用相关的委托方法,您也可以实现身份validation。

解决方法:

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

不是最好的解决scheme,但它的工作原理!

我对这个主题的“推荐”答案感到惊讶。

好,我确定使用asynchronous版本方法更好,但是它仍然不能解释为什么sendSynchronousRequest函数允许你传递一个variables来返回响应代码,但是在某些情况下,它只返回nil

自从这个问题报告4年来 ,我使用iOS 8.2的XCode 6.2,这个古老的bug仍然存在。

当用户的用户名和密码不正确时,我的Web服务会故意返回401错误。

当我的iPhone应用程序调用此服务(凭证错误)…

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

.. response返回为零(所以我不能testingHTTP响应401), error收到-1012消息包装像这样:

  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} 

sendSynchronousRequest函数返回一个冗长的XMLstring包含…嗯…

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

来吧苹果,修正你的错误…

它实际上退出简单。 现在,asynchronous请求确实是一个非常好的帮手。 但是你必须记住它只是一个帮手。 Http只是一个networking协议,因此它不能与用户交互。 换句话说,两种情况实际上是一样的。

如果您不想使用asynchronous帮助程序,则build议您向用户显示一个login对话框,并重复您的请求,直到用户按下取消。

[编辑]

仅供参考,我个人更喜欢curl。 像几乎无处不在的魅力一样;)

我面临的问题是没有收到401未经授权的错误代码(得到零响应也didReceiveResponse方法没有得到调用),而不是收到-999取消错误。 我在我的代码中犯的错误是:在didReceiveChallenge:委托方法,

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

NSURLSessionAuthChallengeCancelAuthenticationChallenge产生了-999错误,并且没有获得401响应。 相反,当我使用completionHandler(NSURLSessionAuthChallengePerformDefaultHandling,零); 按照预期,我在didReceiveResponse:delegate方法中收到401响应。

请注意iOS文档https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/URLLoadingSystem/NSURLSessionConcepts/NSURLSessionConcepts.html ,如果我们取消了urlsession,那么它将被报告为取消,但不是401错误作为回应。

 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.