监听本地URL请求(NSURLProtocol)
2016-03-16 17:39
211 查看
NSURLProtocol 是IOS中非常重要的一个部分,IOS中我们经常使用的网络请求NSURLConnection以及WebView的页面加载都会被NSURLProtocol截获,因此这个部分的核心就是如何来用这个部分:
下面我将根据使用的步骤来描述NSURLProtocol的使用过程:
(1)首先我们需要创建一个类,继承NSURLProtocol并且实现代理继承:
@interfaceMyURLProtocol () <NSURLConnectionDelegate>
@end
(2)在需要使用的地方,注册这个协议。一般情况下,这个协议在AppDelegate文件中注册:
可以正常的使用这个NSURLProtocol只需要简单的使用下面9个方法,这九个方法是这个协议可以实现的最基本和最重要的几个方法,当然它还有很多高级的功能,这里就不一一介绍了。
最重要的9个方法如下:
<1>
@method:创建NSURLProtocol实例,NSURLProtocol注册之后,所有的NSURLConnection都会通过这个方法检查是否持有该Http请求。
@parma :
@return: YES:持有该Http请求NO:不持有该Http请求
+ (BOOL)canInitWithRequest:(NSURLRequest *)request
#pragma mark --NSURLProtocol Hold RelevantMethod 4个方法
<2-5>
@method: NSURLProtocol抽象类必须要实现。通常情况下这里有一个最低的标准:即输入输出请求满足最基本的协议规范一致。因此这里简单的做法可以直接返回。一般情况下我们是不会去更改这个请求的。如果你想更改,比如给这个request添加一个title,组合成一个新的http请求。
@parma :本地HttpRequest请求:request
@return:直接转发
+ (NSURLRequest*)canonicalRequestForRequest:(NSURLRequest *)request
@method: NSURLProtocol缓存系统设置:如果有两个URL请求,并且他们是相等的,那么这里可以使用相同的缓存空间
@parma :本地HttpRequest请求:request
@return:
+ (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest*)b
@method:获取网站上的数据建立connect连接
@parma :
@return:
- (void)startLoading
@method:当前Connection连接取消的时候被调用。尤其要注意这个StopLoading方法,在本地NSURLRequest初始化的时候,有一个超时时间,在低速网络下,有可能页面还没来得及加载完,这个StopLoading方法就被调用了。
@parma :
@return:
- (void)stopLoading
<6-9>接收数据
#pragma mark --NSURLProtocol Delegate 4个方法
- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse *)response
- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data
- (void)connectionDidFinishLoading:(NSURLConnection*)connection
- (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error
注意这里的方法中:
canInitWithRequest 会创建一个实例,YES时候,然后继续调用startLoading。这里会继续调用canInitWithRequest。陷入死循环,因此这里我们常用的做法是设置一个[NSURLProtocolsetProperty:@YESforKey:@"MyURLProtocolHandledKey"inRequest:newRequest];
这样就可以避免程序陷入死循环。
下面给出一段参考代码:
下面我将根据使用的步骤来描述NSURLProtocol的使用过程:
(1)首先我们需要创建一个类,继承NSURLProtocol并且实现代理继承:
@interfaceMyURLProtocol () <NSURLConnectionDelegate>
@end
(2)在需要使用的地方,注册这个协议。一般情况下,这个协议在AppDelegate文件中注册:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [NSURLProtocol registerClass:[MyURLProtocolclass]]; // Override point for customization after application launch. returnYES; }下面就可以使用这个东东了
可以正常的使用这个NSURLProtocol只需要简单的使用下面9个方法,这九个方法是这个协议可以实现的最基本和最重要的几个方法,当然它还有很多高级的功能,这里就不一一介绍了。
最重要的9个方法如下:
<1>
@method:创建NSURLProtocol实例,NSURLProtocol注册之后,所有的NSURLConnection都会通过这个方法检查是否持有该Http请求。
@parma :
@return: YES:持有该Http请求NO:不持有该Http请求
+ (BOOL)canInitWithRequest:(NSURLRequest *)request
#pragma mark --NSURLProtocol Hold RelevantMethod 4个方法
<2-5>
@method: NSURLProtocol抽象类必须要实现。通常情况下这里有一个最低的标准:即输入输出请求满足最基本的协议规范一致。因此这里简单的做法可以直接返回。一般情况下我们是不会去更改这个请求的。如果你想更改,比如给这个request添加一个title,组合成一个新的http请求。
@parma :本地HttpRequest请求:request
@return:直接转发
+ (NSURLRequest*)canonicalRequestForRequest:(NSURLRequest *)request
@method: NSURLProtocol缓存系统设置:如果有两个URL请求,并且他们是相等的,那么这里可以使用相同的缓存空间
@parma :本地HttpRequest请求:request
@return:
+ (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest*)b
@method:获取网站上的数据建立connect连接
@parma :
@return:
- (void)startLoading
@method:当前Connection连接取消的时候被调用。尤其要注意这个StopLoading方法,在本地NSURLRequest初始化的时候,有一个超时时间,在低速网络下,有可能页面还没来得及加载完,这个StopLoading方法就被调用了。
@parma :
@return:
- (void)stopLoading
<6-9>接收数据
#pragma mark --NSURLProtocol Delegate 4个方法
- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse *)response
- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data
- (void)connectionDidFinishLoading:(NSURLConnection*)connection
- (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error
注意这里的方法中:
canInitWithRequest 会创建一个实例,YES时候,然后继续调用startLoading。这里会继续调用canInitWithRequest。陷入死循环,因此这里我们常用的做法是设置一个[NSURLProtocolsetProperty:@YESforKey:@"MyURLProtocolHandledKey"inRequest:newRequest];
这样就可以避免程序陷入死循环。
下面给出一段参考代码:
@implementation MyURLProtocol /** @method: 创建NSURLProtocol实例,NSURLProtocol注册之后,所有的NSURLConnection都会通过这个方法检查是否持有该Http请求。 @parma : @return: YES:持有该Http请求 NO:不持有该Http请求 */ + (BOOL)canInitWithRequest:(NSURLRequest *)request { staticNSUInteger requestCount =0; NSLog(@"Request #%u: URL = %@", requestCount++, request); if([NSURLProtocolpropertyForKey:@"MyURLProtocolHandledKey"inRequest:request]) { returnNO; } returnYES; } #pragma mark --NSURLProtocol Hold Relevant Method /** @method: NSURLProtocol抽象类必须要实现。通常情况下这里有一个最低的标准:即输入输出请求满足最基本的协议规范一致。因此这里简单的做法可以直接返回。一般情况下我们是不会去更改这个请求的。如果你想更改,比如给这个request添加一个title,组合成一个新的http请求。 @parma : 本地HttpRequest请求:request @return: 直接转发 */ + (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest*)request { return request; } /** @method: NSURLProtocol缓存系统设置:如果有两个URL请求,并且他们是相等的,那么这里可以使用相同的缓存空间 @parma : 本地HttpRequest请求:request @return: */ + (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b { return [superrequestIsCacheEquivalent:atoRequest:b]; } - (void)startLoading { NSMutableURLRequest *newRequest = [self.requestmutableCopy]; [NSURLProtocolsetProperty:@YESforKey:@"MyURLProtocolHandledKey"inRequest:newRequest]; self.connection = [NSURLConnectionconnectionWithRequest:newRequestdelegate:self]; } /** @method: 当前Connection连接取消的时候被调用 @parma : @return: */ - (void)stopLoading { [self.connectioncancel]; self.connection =nil; } #pragma mark --NSURLProtocol Delegate - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { [self.clientURLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; } - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { [self.clientURLProtocol:selfdidLoadData:data]; } - (void)connectionDidFinishLoading:(NSURLConnection *)connection { [self.clientURLProtocolDidFinishLoading:self]; } - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { [self.clientURLProtocol:selfdidFailWithError:error]; } @end
相关文章推荐
- 实战 Lucene,第 1 部分: 初识 Lucene
- 初学嵌入式STM32基础下选哪款开发板适合学习
- 获取当前方法名,行号,类名,所在java文件第几行
- Java实现几种常见排序方法
- android FragmentpagerAdapter和FragmentStatePagerAdapter的区别
- sublime Text 3 做c编辑器
- android FragmentpagerAdapter和FragmentStatePagerAdapter的区别
- android FragmentpagerAdapter和FragmentStatePagerAdapter的区别
- IOS:Safari不兼容Javascript中的Date问题
- 软件工程概论个人作业02
- 详解 UIView 的 Tint Color 属性
- 评论接口中插入表情,后台不支持
- ArrayList remove()问题
- Java简单的网络爬虫实现
- CentOS7.1 Liberty云平台之环境准备(2)
- React 复合组件
- 基于zepto的移动端弹出窗口插件
- DOM getElementsByClassName IE兼容方案
- Golang之sdl2学习之路(零) -- 环境工具准备
- java 反射实现不同对象相同属性值复制