【问题标题】:Using NSURLProtocol with NSURLSession使用 NSURLProtocol 和 NSURLSession
【发布时间】:2015-11-20 07:04:04
【问题描述】:

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

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.

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

  1. 注册 [NSURLProtocol registerClass:[CustomHTTPSProtocol class]];使用 NSURLConnection 工作得很好,但是如何使用 NSURLSession 全局地为 NSURLProtocol 进行 Resister 呢?。

  2. 为什么在带有 URLSession 的 NSURLProtocol(相同的 URL 和逻辑与 URLConnection 一起使用)中的请求会失败,以及如何让 NSURLProtocol 与 URLSession 一起使用?。

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

【问题讨论】:

  • 正如@chandra 所说,我在 iOS 8.x 上只收到 -999 错误

标签: ios xcode nsurl nsurlsession nsurlprotocol


【解决方案1】:

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

NSURLSession Api(NS​​URLSessionDataTask 和其他任务类)与自定义 NSUrlProtocol 一起使用时无法正确处理 HTTP 身份验证挑战。 这在 iOS 7.x 上按预期工作,在 iOS 8.x 中被破坏。提出了一个苹果雷达,我的雷达被关闭,说它是另一个雷达的副本,我仍然看到原来的雷达仍然打开。所以我相信苹果到今天还没有解决这个问题。

希望我的答案还不算太晚:)

【讨论】:

  • 有人知道这在 iOS 9.x 还是 10.x 中是否已修复?
  • 我的雷达当前状态仍然是打开的,所以我相信它还没有在 iOS 10.x 中修复。
【解决方案2】:

我知道这很旧,但您遇到的问题在于您的 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。

【讨论】:

    【解决方案3】:

    我的模糊记忆是 NSURLSession 自动使用任何全局注册的协议。因此,您不需要再次注册,但这样做也不会有什么坏处。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-22
      • 2016-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多