[编辑以提供更多信息]
(我没有在这个项目中使用 AFNetworking。我将来可能会这样做,但希望先解决这个问题/误解。)
服务器设置
我不能在这里提供真正的服务,但它是一个简单、可靠的服务,它根据 URL 返回 XML,例如:
https://username:password@example.com/webservice
我想使用 GET 通过 HTTPS 连接到 URL,并确定任何身份验证失败(http 状态代码 401)。
我已确认 Web 服务可用,并且我可以使用指定的用户名和密码成功(http 状态代码 200)从 url 中获取 XML。我已经使用 Web 浏览器和 AFNetworking 2.0.3 以及使用 NSURLConnection 完成了此操作。
我还确认我在所有阶段都使用了正确的凭据。
给定正确的凭据和以下代码:
// Note: NO delegate provided here.
self.sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
self.session = [NSURLSession sessionWithConfiguration:self.sessionConfig
delegate:nil
delegateQueue:nil];
NSURLSessionDataTask *dataTask = [self.session dataTaskWithURL:self.requestURL completionHandler: ...
上面的代码将起作用。它将成功连接到服务器,获取http状态码200,并返回(XML)数据。
问题 1
在凭证无效的情况下,这种简单的方法会失败。在这种情况下,永远不会调用完成块,不提供状态代码 (401),最终任务超时。
尝试的解决方案
我为 NSURLSession 分配了一个委托,并正在处理以下回调:
-(void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
{
if (_sessionFailureCount == 0) {
NSURLCredential *cred = [NSURLCredential credentialWithUser:self.userName password:self.password persistence:NSURLCredentialPersistenceNone];
completionHandler(NSURLSessionAuthChallengeUseCredential, cred);
} else {
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
}
_sessionFailureCount++;
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
{
if (_taskFailureCount == 0) {
NSURLCredential *cred = [NSURLCredential credentialWithUser:self.userName password:self.password persistence:NSURLCredentialPersistenceNone];
completionHandler(NSURLSessionAuthChallengeUseCredential, cred);
} else {
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
}
_taskFailureCount++;
}
问题 1 使用尝试的解决方案时
请注意使用 ivars _sessionFailureCount 和 _taskFailureCount。我使用这些是因为挑战对象的 @previousFailureCount 属性永远不会高级!无论这些回调方法被调用多少次,它始终保持为零。
问题 2 使用尝试的解决方案时
尽管使用了正确的凭据(正如它们与 nil 委托的成功使用所证明的那样),但身份验证失败了。
发生以下回调:
URLSession:didReceiveChallenge:completionHandler:
(challenge @ previousFailureCount reports as zero)
(_sessionFailureCount reports as zero)
(completion handler is called with correct credentials)
(there is no challenge @error provided)
(there is no challenge @failureResponse provided)
URLSession:didReceiveChallenge:completionHandler:
(challenge @ previousFailureCount reports as **zero**!!)
(_sessionFailureCount reports as one)
(completion handler is called with request to cancel challenge)
(there is no challenge @error provided)
(there is no challenge @failureResponse provided)
// Finally, the Data Task's completion handler is then called on us.
(the http status code is reported as zero)
(the NSError is reported as NSURLErrorDomain Code=-999 "cancelled")
(NSError 还提供了一个 NSErrorFailingURLKey,它显示 URL 和凭据是正确的。)
欢迎任何建议!