1.NSURLProtocol简介
1.1 NSURLProtocol作为Client和Server的中间层,接收Client发送的Request,将其发送至Server端,并接收Server端发送的Response,将数据传回Client端 类似一个中转站
1.2 NSURLProtocol,由于她是一个抽象类,正确的使用姿势是,创建NSURLProtocol的子类,通过registerClass:方法将其注册到URL Loading System中,系统会创建协议对象来处理相应的URL请求,我们可以通过NSURLProtocol提供的API接口,来达到存储和检索特定协议的请求数据的目的。
2.NSURLProtocol应用
创建一个NSURLProtocol子类HMMURLProtocol
在application:didFinishLaunchingWithOptions:方法中注册该HMMURLProtocol,一旦注册完毕后,它就有机会来处理所有交付给URL Loading system的网络请求。
子类里边添加方法
/*
创建NSURLProtocol实例,NSURLProtocol注册之后
所有的NSURLConnection都会通过这个方法检查是否持有该Http请求
我们可以在这个方法的实现里面进行请求的过滤,筛选出需要进行处理的请求。
*/
+ (BOOL)canInitWithRequest:(NSURLRequest *)request {};
/*
虽然它与 + canInitWithRequest: 方法传入的 request 对象都是一个
但是最好不要在 + canInitWithRequest: 中操作对象,可能会有语义上的问题
所以,我们需要覆写 + canonicalRequestForRequest 这是一个抽象方法,子类必须实现
一般不修改,需要修改也可以在这个方法里修改
*/
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request
{
return request;
}
/*
如果有两个URL请求,并且他们是相等的,那么这里可以使用相同的缓存空间通常只需要调用父类的实现
*/
+ (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b
{
return [super requestIsCacheEquivalent:a toRequest:b];
}
/*
重点利用的一个方法,可以在里面做判断是否使用缓存,
如果使用缓存,则对数据进行反归档,并直接实现client几个协议方法;
如果不使用缓存,则创建一个NSURLConnection 对象。
*/
-(void)startLoading
{
NSMutableURLRequest *mutableReqeust = [[self request] mutableCopy];
//做下标记,防止递归调用
[NSURLProtocol setProperty:@YES forKey:kPAGURLProtocol inRequest:mutableReqeust];
self.connection = [NSURLConnection connectionWithRequest:mutableReqeust delegate:self];
}
/*
停止相应请求,清空请求Connection 或Task
当前Connection连接取消的时候被调用。尤其要注意这个StopLoading方法,
在本地NSURLRequest初始化的时候,有一个超时时间,在低速网络下,
有可能页面还没来得及加载完,这个StopLoading方法就被调用了。
*/
-(void)startLoading
{
}
/*在得到了需要的请求对象之后,就可以初始化一个 NSURLProtocol 对象了
在这里直接调用 super 的指定构造器方法,实例化一个对象,
然后就进入了发送网络请求,获取数据并返回的阶段了
开始请求在这里需要我们手动的把请求发出去,
可以使用原生的NSURLSessionDataTask,
也可以使用的第三方网络库 同时设置"NSURLSessionDataDelegate"协议,
接收Server端的响应
*/
- (id)initWithRequest:(NSURLRequest *)request cachedResponse:(NSCachedURLResponse *)cachedResponse client:(id <NSURLProtocolClient>)client
{
return [super initWithRequest:request cachedResponse:cachedResponse client:client];
}
NSURLConnectionDataDelegate方法 当接收到Server端的响应时,将其通过"NSURLProtocolClient"协议,转发给URL Loading System
//发生重定向时
- (void)URLProtocol:(NSURLProtocol *)protocol wasRedirectedToRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse;
//接收到响应时
- (void)URLProtocol:(NSURLProtocol *)protocol didReceiveResponse:(NSURLResponse *)response cacheStoragePolicy:(NSURLCacheStoragePolicy)policy;
//成功
- (void)URLProtocolDidFinishLoading:(NSURLProtocol *)protocol;
//失败
- (void)URLProtocol:(NSURLProtocol *)protocol didFailWithError:(NSError *)error;
需要注意的是 NSURLProtocol 只能拦截 UIURLConnection、NSURLSession 和 UIWebView 中的请求,对于 WKWebView 中发出的网络请求也无能为力,如果真的要拦截来自 WKWebView 中的请求,还是需要实现 WKWebView 对应的 WKNavigationDelegate,并在代理方法中获取请求。 无论是 NSURLProtocol、NSURLConnection 还是 NSURLSession 都会走底层的 socket,但是 WKWebView 可能由于基于 WebKit,并不会执行 C socket 相关的函数对 HTTP 请求进行处理,具体会执行什么代码暂时不是很清楚
关于怎么WKWebView使支持NSURLProtocol 可以借鉴 https://juejin.im/post/594a4f0961ff4b006c131862
网友评论