iOS NSURLProtocol的具体使用方法详解
本文介绍了ios nsurlprotocol的具体使用方法详解,分享给大家,具体如下:
nsurlprotocol定义
这两天在优化项目,无意间看到了nsurlprotocol,学习一下顺便总结下来。
nsurlprotocol也是苹果众多黑魔法中的一种,能够让你去重新定义苹果的url加载系统 (url loading system)的行为,url loading system里有许多类用于处理url请求,比如nsurl,nsurlrequest,nsurlconnection和nsurlsession等,当url loading system使用nsurlrequest去获取资源的时候,它会创建一个nsurlprotocol子类的实例,nsurlprotocol看起来像是一个协议,但其实这是一个类,而且必须使用该类的子类,并且需要被注册。
nsurlprotocol使用范围
只要是使用nsurlconnection或者 nsurlsession实现的,你都可以通过nsurlprotocol做一些自定义的操作。
1、自定义请求和响应
2、网络的缓存处理(h5离线包 和 网络图片缓存)
3、重定向网络请求
4、为测试提供数据mocking功能,在没有网络的情况下使用本地数据返回。
5、过滤掉一些非法请求
6、快速进行测试环境的切换
7、拦截图片加载请求,转为从本地文件加载
8、可以拦截uiwebview,基于系统的nsurlconnection或者nsurlsession进行封装的网络请求。目前wkwebview无法被nsurlprotocol拦截。
9、当有多个自定义nsurlprotocol注册到系统中的话,会按照他们注册的反向顺序依次调用url加载流程。当其中有一个nsurlprotocol拦截到请求的话,后续的nsurlprotocol就无法拦截到该请求。
nsurlprotocol自定义
#import <foundation/foundation.h> @interface customurlprotocol : nsurlprotocol @end
要实现下面的方法
+ caninitwithrequest: //抽象方法,子类给出是否能相应该请求。如果响应yes,说明自己的customurlprotocol实现该请求。 + canonicalrequestforrequest: //抽象方法,重写该方法,可以对请求进行修改,例如添加新的头部信息,修改,修改url等,返回修改后的请求。 + requestiscacheequivalent:torequest: //看都是缓存了 - startloading: //开始下载,需要在该方法中发起一个请求,对于nsurlconnection来说,就是创建一个nsurlconnection,对于nsurlsession,就是发起一个nsurlsessiontask 。一般下载前需要设置该请求正在进行下载,防止多次下载的情况发生 - stoploading: //停止相应请求,清空请求connection 或 task
使用自定义nsurlprotocol类
1.在单个的uiviewcontroller中使用
//导入自定义nsurlprotocol类 #import "customurlprotocol.h" //在viewdidload中添加拦截网络请求的代码 //注册网络请求拦截 [nsurlprotocol registerclass:[customurlprotocol class]]; //在viewwilldisappear中添加取消网络拦截的代码 //取消注册网络请求拦截 [nsurlprotocol unregisterclass:[customurlprotocol class]];
2.拦截整个app中所有的网络请求
//直接在appdelegate中的didfinishlaunchingwithoptions注册网络拦截代码 //注册protocol [nsurlprotocol registerclass:[customurlprotocol class]]; nsurlprotocol使用实例 #define urlprotocolhandledkey @"urlprotocolhandledkey" + (bool)caninitwithrequest:(nsurlrequest *)request{ //只处理http和https请求 nsstring *scheme = [[request url] scheme]; if ( ([scheme caseinsensitivecompare:@"http"] == nsorderedsame || [scheme caseinsensitivecompare:@"https"] == nsorderedsame)){ //看看是否已经处理过了,防止无限循环 if ([nsurlprotocol propertyforkey:urlprotocolhandledkey inrequest:request]) { return no; } return yes; } return no; } + (nsurlrequest *) canonicalrequestforrequest:(nsurlrequest *)request { /** 可以在此处添加头等信息 */ nsmutableurlrequest *mutablereqeust = [request mutablecopy]; mutablereqeust = [self redirecthostinrequset:mutablereqeust]; return mutablereqeust; } +(nsmutableurlrequest*)redirecthostinrequset:(nsmutableurlrequest*)request{ if ([request.url host].length == 0) { return request; } nsstring *originurlstring = [request.url absolutestring]; nsstring *originhoststring = [request.url host]; nsrange hostrange = [originurlstring rangeofstring:originhoststring]; if (hostrange.location == nsnotfound) { return request; } //定向薄荷喵到主页 nsstring *ip = @"bohemiao.com"; // 替换域名 nsstring *urlstring = [originurlstring stringbyreplacingcharactersinrange:hostrange withstring:ip]; nsurl *url = [nsurl urlwithstring:urlstring]; request.url = url; return request; } + (bool)requestiscacheequivalent:(nsurlrequest *)a torequest:(nsurlrequest *)b{ return [super requestiscacheequivalent:a torequest:b]; } - (void)startloading{ nsmutableurlrequest *mutablereqeust = [[self request] mutablecopy]; //标示该request已经处理过了,防止无限循环 [nsurlprotocol setproperty:@yes forkey:urlprotocolhandledkey inrequest:mutablereqeust]; self.connection = [nsurlconnection connectionwithrequest:mutablereqeust delegate:self]; //使用nsurlsession也是一样的 } - (void)stoploading{ [self.connection cancel]; } - (void) connection:(nsurlconnection *)connection didreceiveresponse:(nsurlresponse *)response { [self.client urlprotocol:self didreceiveresponse:response cachestoragepolicy:nsurlcachestoragenotallowed]; } - (void) connection:(nsurlconnection *)connection didreceivedata:(nsdata *)data { [self.client urlprotocol:self didloaddata:data]; } - (void) connectiondidfinishloading:(nsurlconnection *)connection { [self.client urlprotocoldidfinishloading:self]; } - (void)connection:(nsurlconnection *)connection didfailwitherror:(nserror *)error { [self.client urlprotocol:self didfailwitherror:error]; }
上面用到的一些nsurlprotocolclient方法
@protocol nsurlprotocolclient <nsobject> //请求重定向 - (void)urlprotocol:(nsurlprotocol *)protocol wasredirectedtorequest:(nsurlrequest *)request redirectresponse:(nsurlresponse *)redirectresponse; // 响应缓存是否合法 - (void)urlprotocol:(nsurlprotocol *)protocol cachedresponseisvalid:(nscachedurlresponse *)cachedresponse; //刚接收到response信息 - (void)urlprotocol:(nsurlprotocol *)protocol didreceiveresponse:(nsurlresponse *)response cachestoragepolicy:(nsurlcachestoragepolicy)policy; //数据加载成功 - (void)urlprotocol:(nsurlprotocol *)protocol didloaddata:(nsdata *)data; //数据完成加载 - (void)urlprotocoldidfinishloading:(nsurlprotocol *)protocol; //数据加载失败 - (void)urlprotocol:(nsurlprotocol *)protocol didfailwitherror:(nserror *)error; //为指定的请求启动验证 - (void)urlprotocol:(nsurlprotocol *)protocol didreceiveauthenticationchallenge:(nsurlauthenticationchallenge *)challenge; //为指定的请求取消验证 - (void)urlprotocol:(nsurlprotocol *)protocol didcancelauthenticationchallenge:(nsurlauthenticationchallenge *)challenge; @end
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。