Использование 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 Canceled возвращается через некоторое время. didReceiveData не вызывается.

Note:NSURLProtocol and the Authentication Process worked fine with NSURLConnection.

Что мне не хватает?? Мои вопросы

  1. Регистрация [NSURLProtocol registerClass: [CustomHTTPSProtocol class]]; отлично работал с NSURLConnection, но как глобально сопротивляться NSURLProtocol с помощью NSURLSession?

  2. Почему запросы не выполняются в NSURLProtocol (тот же URL и логика работают с URLConnection) с URLSession и как заставить NSURLProtocol работать с URLSession?

Пожалуйста, помогите мне и дайте мне знать, если вы хотите получить более подробную информацию.


person vishnuvarthan    schedule 26.08.2015    source источник
comment
Как сказал @chandra, я получаю только ошибку -999 на iOS 8.x   -  person Harrison Xi    schedule 10.01.2019


Ответы (3)


Я знаю, что это старо, но проблема, с которой вы столкнулись, заключается в вашем методе didReceiveChallenge. Вы завершаете метод, вызывая

[challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];

or

[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];

Вместо этого вам нужно использовать обработчик завершения для отправки ваших результатов. Это будет выглядеть так:

completionHandler(.UseCredential, NSURLCredential(forTrust: challenge.protectionSpace.serverTrust)

or

completionHandler(.PerformDefaultHandling, nil)

Они есть в Swift 2.0, но должны хорошо переводиться в Obj-C.

person Chris    schedule 17.08.2016

Регистрация пользовательского NSURLProtocol с помощью NSUrlsession такая же, как и с NSURLConnection.

NSURLSession Api (NSURLSessionDataTask и другие классы задач) при использовании с пользовательским NSUrlProtocol не может правильно обрабатывать запросы проверки подлинности HTTP. Это работало, как и ожидалось, на iOS 7.x и не работает в iOS 8.x. Поднял радар Apple, и мой радар был закрыт, говоря, что это дубликат другого радара, и я все еще вижу, что исходный радар все еще открыт. Поэтому я считаю, что эта проблема еще не решена Apple на сегодняшний день.

Надеюсь, я не опоздала с ответом :)

person Chandra    schedule 08.03.2016
comment
Кто-нибудь знает, было ли это исправлено в iOS 9.x или 10.x? - person Locksleyu; 09.08.2016
comment
Текущий статус моего радара все еще открыт, поэтому я считаю, что он еще не исправлен в iOS 10.x. - person Chandra; 19.10.2016

Насколько я помню, NSURLSession автоматически использует любые глобально зарегистрированные протоколы. Таким образом, вам не нужно регистрировать его снова, но это также не повредит.

Интересно, копируется ли запрос URL, и в этом случае ваши пользовательские теги могут не работать, и вы можете увидеть бесконечную рекурсию, пока она не достигнет некоторого внутреннего предела. Вы пытались вместо этого установить заголовок запроса?

person dgatwood    schedule 28.10.2015