NSURLSessionTaskauthentication挑战completionHandler和NSURLAuthenticationChallenge客户端
我正在实现一个自定义NSURLProtocol
,并在内部想要使用NSURLSession
数据任务的内部networking,而不是NSURLConnection
。
我碰到了一个有趣的问题,并想知道NSURLSession
/ NSURLSessionTask
的质询处理程序的内部实现。
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler;
在这里,我基本上提供了两个不同的挑战处理程序,一个是completionHandler
块,它提供了处理挑战的所有必要的信息,但是也有传统的NSURLAuthenticationChallenge.client
,它具有几乎与一对一对应的方法completionHandler
信息选项。
由于我正在开发一个协议,并且想要向调用API实现的URL加载系统向上传递一定的authentication挑战,我需要使用NSURLSession
客户端方法:
- (void)URLProtocol:(NSURLProtocol *)protocol didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
我的问题是completionHandler
和NSURLAuthenticationChallenge.client
的内部实现是否相同,如果是这样,我可以跳过在委托方法中调用完成处理程序,期望URL加载系统将调用适当的NSURLAuthenticationChallenge.client
方法吗?
回答我自己的问题,答案是否定的。 此外,苹果公司提供的挑战发件人不实施整个NSURLAuthenticationChallengeSender
协议,从而在客户端尝试应对挑战时崩溃:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFURLSessionConnection performDefaultHandlingForAuthenticationChallenge:]: unrecognized selector sent to instance 0x7ff06d958410'
我的解决scheme是创build一个包装:
@interface CPURLSessionChallengeSender : NSObject <NSURLAuthenticationChallengeSender> - (instancetype)initWithSessionCompletionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler; @end @implementation CPURLSessionChallengeSender { void (^_sessionCompletionHandler)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential); } - (instancetype)initWithSessionCompletionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler { self = [super init]; if(self) { _sessionCompletionHandler = [completionHandler copy]; } return self; } - (void)useCredential:(NSURLCredential *)credential forAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { _sessionCompletionHandler(NSURLSessionAuthChallengeUseCredential, credential); } - (void)continueWithoutCredentialForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { _sessionCompletionHandler(NSURLSessionAuthChallengeUseCredential, nil); } - (void)cancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge; { _sessionCompletionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil); } - (void)performDefaultHandlingForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { _sessionCompletionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); } - (void)rejectProtectionSpaceAndContinueWithChallenge:(NSURLAuthenticationChallenge *)challenge { _sessionCompletionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, nil); } @end
我用新包装的发件人replace了挑战对象:
NSURLAuthenticationChallenge* challengeWrapper = [[NSURLAuthenticationChallenge alloc] initWithAuthenticationChallenge:challenge sender:[[CPURLSessionChallengeSender alloc] initWithSessionCompletionHandler:completionHandler]]; [self.client URLProtocol:self didReceiveAuthenticationChallenge:challengeWrapper];