将NSURLProtocol与NSURLSession一起使用

vis*_*han 7 xcode nsurl nsurlprotocol ios 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];
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

调用开始加载并且还完成了身份验证质询,但在此之后立即调用停止加载.

一段时间后返回错误代码-999"已取消".didReceiveData未被调用.

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

我错过了什么?我的问题是

  1. 注册[NSURLProtocol registerClass:[CustomHTTPSProtocol class]]; 使用NSURLConnection工作正常,但如何使用NSURLSession全局抵御NSURLProtocol?

  2. 为什么NSURLProtocol中的请求失败(使用URL链接和逻辑使用URL连接)以及如何使NSURLProtocol使用URLSession?

请帮助我,如果您想了解更多详情,请告诉我.

Chr*_*ris 0

我知道这已经很旧了,但您遇到的问题是在 didReceiveChallenge 方法中。您通过调用结束该方法

[challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
Run Code Online (Sandbox Code Playgroud)

或者

[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
Run Code Online (Sandbox Code Playgroud)

您需要做的是使用完成处理程序来发送结果。它看起来像这样:

completionHandler(.UseCredential, NSURLCredential(forTrust: challenge.protectionSpace.serverTrust)
Run Code Online (Sandbox Code Playgroud)

或者

completionHandler(.PerformDefaultHandling, nil)
Run Code Online (Sandbox Code Playgroud)

这些是 Swift 2.0 中的内容,但应该可以很好地转换为 Obj-C。