分析NSURLProtocol是如何自定义的?如何使用的?
2016-04-29 本文已影响485人
刘书亚的天堂之路
PRHTTPURLProtocol.h文件
#import <Foundation/Foundation.h>
//继承自NSURLProtocol
@interface PRHTTPURLProtocol : NSURLProtocol
@end
PRHTTPURLProtocol.m文件
#import "PRHTTPURLProtocol.h"
#import "PRCachedURLResponse.h"
//自定义唯一标示符
static NSString *const PRHTTPURLProtocolHandledKey = @"PRHTTPURLProtocolHandledKey";
@interface PRHTTPURLProtocol ()
@property (nonatomic, strong) NSURLConnection *connection;//网络连接对象
@property (nonatomic, strong) NSMutableData *data;//网络请求返回数据
@property (nonatomic, strong) NSURLResponse *response;//网络返回封装对象(包含,数据,格式,请求链接等等)
@end
@implementation PRHTTPURLProtocol
//说白了这个函数是用来过滤网络请求的协议的,即满足我设置的协议就给你返回yes,允许你进行网络通信,一旦返回no后续的网络请求将不会被继续执行
+ (BOOL)canInitWithRequest:(NSURLRequest *)request
{
//如果是非http https就不让他通过
if (![request.URL.scheme isEqualToString:@"http"] && ![request.URL.scheme isEqualToString:@"https"]) {
return NO;
}
//看看是否已经处理过了,防止无限循环,如果已经处理过(即设置了允许通过,就不再初始化了)
if ([NSURLProtocol propertyForKey:PRHTTPURLProtocolHandledKey inRequest:request]) {
return NO;
}
return YES;
}
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request
{
return request;
}
- (void)startLoading
{
//如果有缓存,就直接返回缓存的结果
NSString *cacheKey = self.request.URL.absoluteString;
PRCachedURLResponse *cachedResponse = [[CWObjectCache sharedCache] objectForKey:cacheKey];
if (cachedResponse && cachedResponse.response && cachedResponse.data) {
NSURLResponse *response = cachedResponse.response;
NSData *data = cachedResponse.data;
[self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
[self.client URLProtocol:self didLoadData:data];
[self.client URLProtocolDidFinishLoading:self];
return;
}
//没有缓存 返回这个新的请求
NSMutableURLRequest *newRequest = [self.request mutableCopy];
[newRequest setTimeoutInterval:15];
//打标签,防止无限循环
[NSURLProtocol setProperty:@YES forKey:PRHTTPURLProtocolHandledKey inRequest:newRequest];
self.connection = [NSURLConnection connectionWithRequest:newRequest delegate:self];
}
- (void)stopLoading
{
[self.connection cancel];
}
#pragma mark - NSURLConnection delegate
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
// cache image only
NSString *MIMEType = [response.MIMEType lowercaseString];
if (![MIMEType hasPrefix:@"image"]) {
return;
}
//保存网络获取的数据和数据对象
self.data = [[NSMutableData alloc] init];
self.response = response;
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[[self client] URLProtocol:self didLoadData:data];
//累加数据
[self.data appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[[self client] URLProtocol:self didFailWithError:error];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[[self client] URLProtocolDidFinishLoading:self];
if (!self.response || [self.data length] == 0) {
return;
}
//缓存对应url的数据和数据对象(序列化)
PRCachedURLResponse *cache = [[PRCachedURLResponse alloc] init];
cache.response = self.response;
cache.data = self.data;
[[CWObjectCache sharedCache] storeObject:cache forKey:[[self.request URL] absoluteString]];
}
- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response
{
if (response) {
// simply consider redirect as an error
NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorResourceUnavailable userInfo:nil];
[[self client] URLProtocol:self didFailWithError:error];
}
return request;
}
- (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];
}
@end