Использование NSURLProtocol с NSURLSession
Мое приложение использует 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, но как противостоять NSURLProtocol глобально с помощью NSURLSession ?.
Почему происходит ли сбой запросов в NSURLProtocol(тот же URL и логика работали с urlconnection) с URLSession и как заставить NSURLProtocol работать с URLSession ?.
3 ответа:
Я знаю, что это старый, но проблема, с которой вы столкнулись, заключается в вашем методе 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.
Регистрация пользовательского NSURLProtocol с помощью NSUrlsession аналогична регистрации NSURLConnection.
Api NSURLSession (NSURLSessionDataTask и другие классы задач) при использовании с пользовательским NSUrlProtocol не справляется с проблемами проверки подлинности HTTP должным образом. Это работало, как и ожидалось на iOS 7.x и сломан в iOS 8.x. поднял радар apple, и мой радар был закрыт, говоря, что это дубликат другого радара, и я все еще вижу, что оригинальный радар все еще открыт. Так что я верю в это. проблема еще не решена компанией apple на сегодняшний день.
Надеюсь, я не слишком опоздал с ответом:)
Мое смутное воспоминание состоит в том, что NSURLSession автоматически использует любые глобально зарегистрированные протоколы. Так что вам не нужно будет регистрировать его снова, но это также не повредит сделать это.
Интересно, копируется ли запрос URL, и в этом случае ваш пользовательский тег может не работать, и вы можете видеть бесконечную рекурсию, пока она не достигнет некоторого внутреннего предела. Вы пробовали установить заголовок запроса вместо этого?