博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
IOS网络篇1之截取本地URL请求(NSURLProtocol)
阅读量:7137 次
发布时间:2019-06-28

本文共 4604 字,大约阅读时间需要 15 分钟。

本文转载至 http://blog.csdn.net/u014011807/article/details/39894247

NSURLProtocol 是中非常重要的一个部分,我们经常会在以下地方用到它:

(1)网络请求代理转发(FQ 网络加速等)

(2)离线缓存策略

总之,只要是需要对本地的URL请求进行截获的,我们都需要使用这个东东。

IOS中我们经常使用的网络请求NSURLConnection以及WebView的页面加载都会被NSURLProtocol截获,因此这个部分的核心就是如何来用这个部分:

下面我将根据使用的步骤来描述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;

}

下面就可以使用这个东东了

(3)下面准备好一段WebView的页面加载代码,这个太简单了,不详细说了,给一个参考代码:

 

- (void) sendRequest {

    

   NSString *text =self.textField.text;

   if (![textisEqualToString:@""]) {

       NSURL *url = [NSURLURLWithString:text];

       NSURLRequest *request = [NSURLRequestrequestWithURL:url];

        [self.webView loadRequest:request];

    }    

}

(4)可以正常的使用这个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];

这样就可以避免程序陷入死循环。

(5)下面给出一段参考代码:

 

@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

你可能感兴趣的文章
归并排序
查看>>
Unsupported major.minor version 51.0解决办法
查看>>
windows phone 7 基本导航
查看>>
sizeof(数组名) 及strlen(数组名)
查看>>
android visible invisible和gone的区别
查看>>
JsTree异步加载数据实现多级菜单
查看>>
部署jar到linux ,开机自启动
查看>>
Continuously INFO JobScheduler:59 - Added jobs for time *** ms, in my Spark Standalone Cluster
查看>>
Spark Streaming之dataset实例
查看>>
sql编程
查看>>
mybatis报错Type interface xxx.Dao is not known to the MapperRegistry
查看>>
第二章笔记
查看>>
简单的数据生成方法
查看>>
映射(map)
查看>>
【转载】nodejs+express+ejs+mongoose实例
查看>>
IOS SDWebImage 支持webp
查看>>
国内不谈java
查看>>
比较Maven和Ant
查看>>
poj 3468 A Simple Problem with Integers(线段树+区间更新+区间求和)
查看>>
dup和dup2函数
查看>>