关于ios:将NSURLProtocol与NSURLSession一起使用

Using NSURLProtocol with NSURLSession

我的应用程序使用NSURLConnection与服务器通信。我们使用https进行通信。为了在一个地方处理所有请求的身份验证,我使用了NSURLProtocol并在该类的委托中处理身份验证。现在,我决定使用NSURLSession而不是NSURLConnection。我正在尝试让NSURLProtocolNSURLSession一起工作
我创建了一个任务,并由

使用了NSURLProtocol

1
2
3
4
5
6
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];

我的NSURLProtocol类的

CustomHTTPSProtocol看起来像这样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
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

调用开始加载,也执行身份验证质询,但此后立即调用停止加载。

Error code -999"Cancelled" is returned after some time. didReceiveData is not called.

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

我想念什么?我的问题是

  • Registering [NSURLProtocol registerClass:[CustomHTTPSProtocol class]]; worked fine with NSURLConnection but how to Resister for NSURLProtocol Globally with NSURLSession ?.

  • Why are the requests getting failed in NSURLProtocol(same URL and logic worked withURLConnection) with URLSession and how to get NSURLProtocol working with URLSession ?.

  • 请帮助我,如果您需要更多详细信息,请告诉我。


    使用NSUrlsession注册自定义NSURLProtocol与使用NSURLConnection进行注册的方式相同。

    NSURLSession Api(NS??URLSessionDataTask和其他任务类)与自定义NSUrlProtocol一起使用时,无法正确处理HTTP身份验证质询。
    这在iOS 7.x上可以正常工作,在iOS 8.x上坏了。举起一个苹果雷达,我的雷达关闭了,说它是另一个雷达的副本,我仍然看到原来的雷达仍然打开。因此,我认为到目前为止,Apple尚未解决此问题。

    希望我回答的时间还不算太晚:)


    我知道这很旧,但是您遇到的问题出在didReceiveChallenge方法中。您正在通过调用

    结束该方法

    1
    [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];

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

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

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

    1
    completionHandler(.PerformDefaultHandling, nil)

    它们在Swift 2.0中,但是应该可以很好地转换为Obj-C。


    我模糊的回忆是NSURLSession自动使用任何全局注册的协议。因此,您无需再次注册,但这样做也无妨。

    我想知道是否复制了URL请求,在这种情况下,您的自定义标记可能无法工作,并且您可能会看到无限递归,直到达到某个内部限制为止。您是否尝试过设置请求标头?