0

我正在子类化NSURLProtocol以拦截 HTTP 请求。

这是自定义NSURLProtocol类。

+ (BOOL)canInitWithRequest:(NSURLRequest *)request {
    if (NSOrderedSame != [request.URL.scheme caseInsensitiveCompare:@"http"] &&
        NSOrderedSame != [request.URL.scheme caseInsensitiveCompare:@"https"]) {
        return NO;
    }

    if ([NSURLProtocol propertyForKey:kURLProtocolRequestHandledKey inRequest:request] ) {
        return NO;
    }

    return YES;
}

+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
    NSMutableURLRequest *mutableReqeust = [request mutableCopy];
    [NSURLProtocol setProperty:@YES forKey:kURLProtocolRequestHandledKey inRequest:mutableReqeust];
    return [mutableReqeust copy];
}

- (void)startLoading {
    self.startDate = [NSDate date];
    self.data = [NSMutableData data];
    self.error = nil;

    self.connection = [[NSURLConnection alloc] initWithRequest:[[self class] canonicalRequestForRequest:self.request] delegate:self startImmediately:YES];
}

- (void)stopLoading {
    [self.connection cancel];
}

#pragma mark - NSURLConnectionDelegate

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    [[self client] URLProtocol:self didFailWithError:error];
    self.error = error;
}

- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)connection {
    return YES;
}

- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
    [[self client] URLProtocol:self didReceiveAuthenticationChallenge:challenge];
}

- (void)connection:(NSURLConnection *)connection didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
    [[self client] URLProtocol:self didCancelAuthenticationChallenge:challenge];
}

#pragma mark - NSURLConnectionDataDelegate

- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response {
    if (response != nil){
        _response = response;
        NSMutableURLRequest *redirect = [request mutableCopy];
        redirect.URL = request.URL;
        [NSURLProtocol setProperty:@NO forKey:kURLProtocolRequestHandledKey inRequest:redirect];
        [[self client] URLProtocol:self wasRedirectedToRequest:redirect redirectResponse:response];

        return redirect;
    }
    return request;
}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageAllowed];
    _response = response;
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    [[self client] URLProtocol:self didLoadData:data];
    [self.data appendData:data];
}

- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse {
    return cachedResponse;
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    [[self client] URLProtocolDidFinishLoading:self];
}

- (void)connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite {

}

我添加一个UIWebView作为子视图,然后加载一个 URL http://ln.clientaccess.10086.cn/shop/optical/Appointment?channel=007&PHONE_NUM=18240235054&AREA_CODE=240&key=4A35774433BA79EB950EDE4B5C4D7121,在控制器被解除后,应用程序被冻结,即使我- stopLoading在 webView 被解除之前调用它也是如此。

这是线程堆栈:

在此处输入图像描述

4

2 回答 2

0

使用startImmediately:NO代替startImmediately:YES将解决这个问题。

    if (currentRunLoop && [currentRunLoop currentMode]) {
        self.connection = [[NSURLConnection alloc] initWithRequest:[[self class] canonicalRequestForRequest:self.request] delegate:self startImmediately:NO];
        [self.connection scheduleInRunLoop:currentRunLoop forMode:[[NSRunLoop currentRunLoop] currentMode]];
        [self.connection start];

    } else {
        self.connection = [[NSURLConnection alloc] initWithRequest:[[self class] canonicalRequestForRequest:self.request] delegate:self startImmediately:YES];
    }

是有线的。有人能告诉我为什么吗?

于 2016-02-15T08:34:34.953 回答
0

我认为您不想修改 canonicalRequest 中的请求——别管它。您确实想在 startLoading 中修改它,并在对 NSURLConnection 的新调用中使用修改后的请求,以便您的协议在该调用期间不会再次处理它。

第二件事是重定向实现可能是错误的——该方法在两种情况下被调用;发送请求时一次(并且重定向为零);您想在这种情况下返回请求(您会这样做)。第二个是当您实际获得重定向时;你想调用客户端(你是)但你想返回 nil,以便让客户端实际处理重定向(否则非 nil 返回可以指示重定向已被处理)。

我不确定其中任何一个都会导致问题,但它们是不同的。

我看到的与我已经实现的唯一不同的是 startImmediately:YES 。虽然这是默认设置,所以这不应该是一个问题。如果以上都没有,也许尝试避免缓存,看看是否有帮助。或者确保在 dealloc 中的连接上调用 -cancel。

于 2016-02-15T02:14:28.993 回答