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& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc& 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.