代码之家  ›  专栏  ›  技术社区  ›  vishnuvarthan

在NSURLSession中使用NSURLProtocol

  •  7
  • vishnuvarthan  · 技术社区  · 9 年前

    我的应用程序使用 NSURLConnection 以与服务器通信。我们使用https进行通信。为了在一个地方处理来自所有请求的身份验证,我使用了 NSURLProtocol 并在该类的委托中处理身份验证。现在我决定使用 NSURLSession 而不是 NSURL连接 。我正在努力 NSURL协议 使用 NSURLS会话 我创建了一个任务并使用 NSURL协议 通过

    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 这是我的 NSURL协议 类看起来像这样

    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?。

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

    请帮助我,如果你想了解更多细节,请告诉我。

    3 回复  |  直到 4 年前
        1
  •  3
  •   Chandra    6 年前

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

    与自定义NSUrlProtocol一起使用时,NSURLSession Api(NSURLSession DataTask和其他任务类)无法正确处理HTTP身份验证挑战。 这在iOS 7.x上按预期工作,在iOS 8.x中被破坏。举起一个苹果雷达,我的雷达被关闭,说它是另一个雷达的复制品,我仍然看到原来的雷达仍然打开。因此,我相信苹果公司至今仍未解决这个问题。

    希望我的回答不会太晚:)

        2
  •  0
  •   Chris    8 年前

    我知道这已经过时了,但你遇到的问题是你的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
  •  0
  •   dgatwood    9 年前

    我模糊地记得NSURLSession自动使用任何全球注册的协议。因此,您不需要再次注册它,但这样做也不会造成伤害。

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