iOS网络(三)

1,103 阅读2分钟

一、NSURLProtocol网络拦截

  • NSURLProtocol是抽象类,使用时要使用其子类

    // 使用子类需先注册
    [NSURLProtocol registerClass:[SONURLProtocol class]];
    
    // 子类实现
    + (BOOL)canInitWithRequest:(NSURLRequest *)request
    {
      	NSLog(@"*** %@",request);
      	//  能监听uiwebview和WKWebview,但是不能拦截WKWebview只能拦截uiwebview
      	//  因为WKWebview走的WebKit,同时不走cookie,走的也是webkit,用的另外一套内核
      	//  connection可以拦截成功,session不行
      	
      	//ProtocolKey 经过标记的request不处理,防止出现自循环(最好经过md5或其他方式处理保证唯一性)
        if ([NSURLProtocol propertyForKey:ProtocolKey inRequest:request]) 
        {
            return NO;
        }
      	
      	// 拦截百度的logo
        if ([[request.URL absoluteString] isEqualToString:@"https://m.baidu.com/static/index/plus/plus_logo_web.png"]) 
        {
            return YES;//  拦截后会新发起新任务执行startLoading  ↓
        }
      
      	// 直接hook 所有图片
        NSArray *array = @[@"png",@"jpg",@"jpeg"];
        if ([array containsObject:[request.URL pathExtension]]) 
        {
            return YES;
        }
      
      	return NO;// 不接受hook处理,直接加载原数据
      	// 重定向,对每次的网络请求都可以监听
    }
    
    - (void)startLoading
    {
      	// 拦截并给与自己数据  ↑
      	// 用于 代码注入、去广告等
        if ([[self.request.URL absoluteString] isEqualToString:@"https://m.baidu.com/static/index/plus/plus_logo_web.png"]) 
        {
            NSData *data = [self getImageData];
            [self.client URLProtocol:self didLoadData:data];
        }
    }
    
  • 拦截session

    需要特殊处理,因为session不走自定义的NSURLProtocol子类,session有自己的NSURLProtocol子类

    afn也是走的session

    // 拦截session的特殊处理
    + (void)hookNSURLSessionConfiguration
    {
        Class cls = NSClassFromString(@"__NSCFURLSessionConfiguration") ?: NSClassFromString(@"NSURLSessionConfiguration");
        
        Method originalMethod = class_getInstanceMethod(cls, @selector(protocolClasses));
        Method stubMethod = class_getInstanceMethod([self class], @selector(protocolClasses));
        if (!originalMethod || !stubMethod) 
        {
            [NSException raise:NSInternalInconsistencyException format:@"没有这个方法 无法交换"];
        }
        method_exchangeImplementations(originalMethod, stubMethod);
    }
    
    - (NSArray *)protocolClasses 
    {
        return @[[SONURLProtocol class]];
        //如果还有其他的监控protocol,也可以在这里加进去
    }
    

二、cookie

WKWebview带不上httpcookie

因为用的不是一套东西,WKWebview用的webkit,沙盒里找不到cookie

//  解决办法:拉取同步NSHTTPCookie
- (IBAction)didClickCookieAction:(id)sender 
{
    WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
   
    self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:configuration];
    self.webView.navigationDelegate = self;
    [self.view addSubview:self.webView];

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com"]];
    [self.webView loadRequest:[self cookieAppendRequest]];
   
}

- (NSURLRequest *)cookieAppendRequest
{
  	// 替换header
  	// 该方法在跨域请求时会丢cookie  ----  解决办法看下面  ↓
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com"]];
    NSArray *cookies = [NSHTTPCookieStorage sharedHTTPCookieStorage].cookies;
    //Cookies数组转换为requestHeaderFields
    NSDictionary *requestHeaderFields = [NSHTTPCookie requestHeaderFieldsWithCookies:cookies];
    //设置请求头
    request.allHTTPHeaderFields = requestHeaderFields;
    NSLog(@"%@",request.allHTTPHeaderFields);
    return request;
}
// 跨域请求时会丢cookie的解决 ↑
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler 
{
    //  WKWebview所有请求动作都会来这里
    [[WKCookieManager shareManager] fixNewRequestCookieWithRequest:navigationAction.request];
    decisionHandler(WKNavigationActionPolicyAllow);
}

- (NSURLRequest *)fixNewRequestCookieWithRequest:(NSURLRequest *)originalRequest
{
    NSMutableURLRequest *fixedRequest;
    if ([originalRequest isKindOfClass:[NSMutableURLRequest class]]) 
    {
        fixedRequest = (NSMutableURLRequest *)originalRequest;
    } 
  	else
    {
        fixedRequest = originalRequest.mutableCopy;
    }
    //防止Cookie丢失
    NSDictionary *dict = [NSHTTPCookie requestHeaderFieldsWithCookies:[NSHTTPCookieStorage sharedHTTPCookieStorage].cookies];
    if (dict.count) 
    {
        NSMutableDictionary *mDict = originalRequest.allHTTPHeaderFields.mutableCopy;
        [mDict setValuesForKeysWithDictionary:dict];
        fixedRequest.allHTTPHeaderFields = mDict;
    }
    return fixedRequest;
}

三、构建HTTP网络框架

  • url-request-请求时间/请求序列化/蜂窝/formadata/url处理(%编码)

  • 构建request的目标是发起task任务,session利用request来构建task

  • 封装:1、在vc中摒弃任何接口

    ​ 2、在vc中不进行数据处理

1、manager类

用于收集:url、timeout、post/get、回调(block、delegate)

2、代理层

session代理数据

3、request层

处理url

4、error
5、缓存
6、工具层

加密、网络状态

7、response

json、xml

8、数据返回层

json → model、mvvm、rac(signal、subscriNext)