一、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)