NSURLProtocol 简单理解

作者: 夕儿77 | 来源:发表于2019-02-18 16:04 被阅读6次

    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

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

    相关文章

      网友评论

        本文标题:NSURLProtocol 简单理解

        本文链接:https://www.haomeiwen.com/subject/hlcaeqtx.html