UIWebView-WKWebView-NSURLProtocol

NSURLProtocol 简单理解

2019-02-18  本文已影响6人  夕儿77

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

以上看大家博客借鉴总结,欢迎大家批评指正补充 ,我是一个小码农。

上一篇下一篇

猜你喜欢

热点阅读