网络三

作者: 纳兰沫 | 来源:发表于2020-04-29 10:58 被阅读0次

NSURLProtocol

需在控制器里面进行注册 [NSURLProtocol registerClass:自定义NSURLProtocol子类];
注册之后 所有的request都要通过下面的方法判断是否需要被处理

+ (BOOL)canInitWithRequest:(NSURLRequest *)request

当返回的是NO的时候 代表request不遵守这个协议 当返回YES的时候代表遵守协议
NSURLProtocol 是无法对WkWebView进行拦截的,因为WkWebView 走的是WebKit内核 cookie也是走的这个流程
可以用来筛选request 重定向,监听进行操作,处理http https

- (void)startLoading

当在+ (BOOL)canInitWithRequest:(NSURLRequest *)request返回YES 要在startLoading里面进行相关的操作,如果在startLoading里面没有进行相应的处理,那么就相关链接会加载不出来
有以下用法

  • 可以拦截图片 进行替换
 if ([[self.request.URL absoluteString] isEqualToString:@"https://m.baidu.com/static/index/plus/plus_logo_web.png"]) {
        NSString *fileName = [[NSBundle mainBundle] pathForResource:@"lufei.jpg" ofType:@""];
        NSDate *data =  [NSData dataWithContentsOfFile:fileName];
        [self.client URLProtocol:self didLoadData:data];
  }
  • 可以拦截所有的图片 进行替换
NSArray *array = @[@"png",@"jpg",@"jpeg"];
if ([array containsObject:[self.request.URL pathExtension]]) {
    NSString *fileName = [[NSBundle mainBundle] pathForResource:@"lufei.jpg" ofType:@""];
    NSDate *data =  [NSData dataWithContentsOfFile:fileName];
    [self.client URLProtocol:self didLoadData:data];
}
  • 拦截url地址 进行重定向

由于这个是自循环的 重定向的时候 不希望他再被+ (BOOL)canInitWithRequest:(NSURLRequest *)request 拦截,可以为不想被拦截的url设置一个key 然后在+ (BOOL)canInitWithRequest:(NSURLRequest *)request 方法中

static NSString *const lmProtocolKey = @"lmProtocolKey";
if ([NSURLProtocol propertyForKey:lmProtocolKey inRequest:request]) {
      return NO;
}

在- (void)startLoading 中

[NSURLProtocol setProperty:@(YES) forKey:lmProtocolKey inRequest:request];

NSURLProtocol的其他方法

+ (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b {
    return [super requestIsCacheEquivalent:a toRequest:b];
}

用来判断两个请求是否是同一个请求
如果是,则可以使用缓存数据,通常只需要调用父类的实现即可,默认为YES,而且一般不在这里做事情

session无法hook成功

使用NSURLProtocol hook成功的标准是原先的request没有发送出去,对于url来说 可以直接hook成功 但是 对于session来说 没有完全成功拦截(因为session.configuration.protocolClasses不含有NSURLProtocol的类 )需要对session的protocolClasses进行方法交换来实现hook

+ (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 @[[LMURLProtocol class],[NSURLHTTPProtocol class],[NSURLDataProtocol Class],[NSURLFTPProtocol Class],
[NSURLFileProtocol Class],[NSAboutURLProtocol Class]];
    //如果还有其他的监控protocol,也可以在这里加进去
}

在数组里面加上原先的class对象 以免造成不可预知的问题
然后在控制器里面进行注册

[LMURLProtocol hookNSURLSessionConfiguration];

WKWebView的cookie

对于WKWebView无法得到cookie的问题 可以直接把cookie加到header

[self setCookieWithDomain:@"http://www.baidu.com" sessionName:@"cooci_token_UIWebView" sessionValue:@"123456789" expiresDate:nil];
NSDictionary *headerDict = [NSHTTPCookie requestHeaderFieldsWithCookies:[NSHTTPCookieStorage sharedHTTPCookieStorage].cookies];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com"]];
request.allHTTPHeaderFields = headerDict;
[self.webView loadRequest:request];

所有的请求都会经过下列方法

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler

当WKWebView跨域,使用request.allHTTPHeaderFields方法无法解决cookie丢失的问题 用如下方法解决

  • 在- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler方法里面进行cookie的注入
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
    [[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;
    }
    NSDictionary *dict = [NSHTTPCookie requestHeaderFieldsWithCookies:[NSHTTPCookieStorage sharedHTTPCookieStorage].cookies];
    if (dict.count) {
        NSMutableDictionary *mDict = originalRequest.allHTTPHeaderFields.mutableCopy;
        [mDict setValuesForKeysWithDictionary:dict];
        fixedRequest.allHTTPHeaderFields = mDict;
    }
    return fixedRequest;
}
  • 脚本注入(效果不是太好)
WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
WKUserContentController *contoller = [[WKUserContentController alloc] init];
[contoller addUserScript:[[WKCookieManager shareManager] futhureCookieScript]];
configuration.userContentController = contoller;
self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:configuration];
self.webView.navigationDelegate = self;
[self.view addSubview:self.webView];
[self.webView loadRequest:[self cookieAppendRequest]];
- (NSURLRequest *)cookieAppendRequest{
    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;
}
- (WKUserScript *)futhureCookieScript{
    WKUserScript * cookieScript = [[WKUserScript alloc] initWithSource:[self cookieString] injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
    return cookieScript;
}
- (NSString *)cookieString
{
    NSMutableString *script = [NSMutableString string];
    [script appendString:@"var cookieNames = document.cookie.split('; ').map(function(cookie) { return cookie.split('=')[0] } );\n"];
    for (NSHTTPCookie *cookie in [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]) {
        if ([cookie.value rangeOfString:@"'"].location != NSNotFound) {
            continue;
        }
        [script appendFormat:@"if (cookieNames.indexOf('%@') == -1) { document.cookie='%@'; };\n", cookie.name, cookie.kc_formatCookieString];
    }
    return script;
}
  • WKWebsiteDataStore(iOS11以上)
[[WKWebsiteDataStore defaultDataStore] httpCookieStore]

设置一个WKWebsiteDataStore就可以解决cookie丢失的问题,当你需要更新cookie的时候重新设置即可

相关文章

  • 网络三

    OSI七层模型 每一层的协议如下:物理层:RJ45、CLOCK、IEEE802.3 (中继器,集线器,网关)...

  • 网络三

    NSURLProtocol 需在控制器里面进行注册 [NSURLProtocol registerClass:自定...

  • 2018-06-05 三层网络结构(核心层 汇聚层 接入层)

    转载自:三层网络结构(核心层 汇聚层 接入层)三层网络结构: 三层网络结构是采用层次化架构的三层网络。三层网络架构...

  • 网络层(三)

    五、因特网的路由选择协议 不存在一种绝对的最佳路由算法。所谓“最佳”只能是相对于某一种特定要求下得出的较为合理的选...

  • 《网络素养》三

    参与的力量 在网络世界里,参与行为本身能够创造独特的归属感,能够完善个人自我。参与的力量在于和他人分享。数字参与素...

  • 网络基础(三)

    1.网络上所抓到的TCP数据报文段中,有一个字段RcvWindow,其含义和作用为:接收窗口大小,用于流量控制。 ...

  • 网络学习三

    关于TCP握手和挥手告别 tcp协议格式 三次握手 在 TCP/IP 协议中,TCP 协议提供可靠的连接服务,采用...

  • 网络编程(三)

    Volley用法完全解析 从上图可以看到Volley分为三个线程,分别是主线程、缓存调度线程、和网络调度线程,首先...

  • 网络协议(三)

    以下内容来自于小码哥"网络协议从入门到底层原理" 计算机之间的连接方式: 网线直连, 同轴电缆, 集线器, 网桥,...

  • 网络爬虫(三)

    这个例子是爬取百度翻译,利用网页中ajax对传入单词进行翻译。 百度翻译运用AJAX对录入的英文进行翻译,采用po...

网友评论

      本文标题:网络三

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