我的应用程序使用NSURLConnection
与服务器通信。我们使用https进行通信。为了在一个地方处理来自所有请求的身份验证,我使用NSURLProtocol
并在该类中的委托中处理身份验证。现在我决定使用NSURLSession
代替NSURLConnection
。我正在努力让NSURLProtocol
与NSURLSession
合作
我创建了一个任务,并使用了NSURLProtocol
NSMutableURLRequest *sampleRequest = [[NSMutableURLRequest alloc]initWithURL:someURL];
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
configuration.protocolClasses = @[[CustomHTTPSProtocol class]];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
NSURLSessionDataTask *task = [session dataTaskWithRequest:checkInInfoRequest];
[task resume];
CustomHTTPSProtocol
这是我的NSURLProtocol
类看起来像这样
static NSString * const CustomHTTPSProtocolHandledKey = @"CustomHTTPSProtocolHandledKey";
@interface CustomHTTPSProtocol () <NSURLSessionDataDelegate,NSURLSessionTaskDelegate,NSURLSessionDelegate>
@property (nonatomic, strong) NSURLSessionDataTask *connection;
@property (nonatomic, strong) NSMutableData *mutableData;
@end
@implementation CustomHTTPSProtocol
+ (BOOL)canInitWithRequest:(NSURLRequest *)request {
if ([NSURLProtocol propertyForKey:CustomHTTPSProtocolHandledKey inRequest:request]) {
return NO;
}
return [[[[request URL]scheme]lowercaseString]isEqualToString:@"https"];
}
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
return request;
}
- (void) startLoading {
NSMutableURLRequest *newRequest = [self.request mutableCopy];
[NSURLProtocol setProperty:@YES forKey:CustomHTTPSProtocolHandledKey inRequest:newRequest];
NSURLSession*session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil];
self.connection = [session dataTaskWithRequest:newRequest];
[self.connection resume];
self.mutableData = [[NSMutableData alloc] init];
}
- (void) stopLoading {
[self.connection cancel];
self.mutableData = nil;
}
-(void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler {
NSLog(@"challenge..%@",challenge.protectionSpace.authenticationMethod);
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
}
else {
[challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}
}
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
[self.client URLProtocol:self didLoadData:data];
NSLog(@"data ...%@ ",data); //handle data here
[self.mutableData appendData:data];
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
if (!error) {
[self.client URLProtocolDidFinishLoading:self];
}
else {
NSLog(@"error ...%@ ",error);
[self.client URLProtocol:self didFailWithError:error];
}
}
@end
调用开始加载并完成身份验证质询,但在此之后立即调用停止加载。
错误代码-999“已取消”在一段时间后返回。不调用didReceiveData。
Note:NSURLProtocol and the Authentication Process worked fine with NSURLConnection.
我错过了什么?我的问题是
注册[NSURLProtocol registerClass:[CustomHTTPSProtocol class]];使用NSURLConnection工作正常,但如何使用NSURLSession全局抵御NSURLProtocol?
- 醇>
为什么NSURLProtocol中的请求失败(使用URL链接和逻辑使用URL连接)以及如何使NSURLProtocol使用URLSession?
如果您想了解更多细节,请帮助我并告诉我。
答案 0 :(得分:3)
使用NSUrlsession注册自定义NSURLProtocol与使用NSURLConnection的方式相同。
NSURLSession Api(NSURLSessionDataTask和其他任务类)与自定义NSUrlProtocol一起使用时无法正确处理HTTP身份验证挑战。 这在iOS 7.x上按预期工作,在iOS 8.x中被破坏。发现了一个苹果雷达,我的雷达被关闭,说它是另一个雷达的副本,我仍然看到原始雷达仍然打开。所以我相信这个问题至今尚未被苹果公司解决。
希望我答案不会太迟:)
答案 1 :(得分:0)
我模糊的回忆是NSURLSession自动使用任何全球注册的协议。所以你不应该再次注册它,但这样做也不会有什么坏处。
我想知道是否要复制URL请求,在这种情况下,您的自定义标记可能不起作用,并且您可能会看到无限递归,直到它达到某个内部限制。您是否尝试过设置请求标头?
答案 2 :(得分:0)
我知道这是旧的,但你遇到的问题是你的didReceiveChallenge方法。您正在通过调用
结束该方法[challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
或
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
您需要做的是使用完成处理程序来发送结果。它看起来像这样:
completionHandler(.UseCredential, NSURLCredential(forTrust: challenge.protectionSpace.serverTrust)
或
completionHandler(.PerformDefaultHandling, nil)
这些都在Swift 2.0中,但应该很好地转换为Obj-C。