网络框架
NSURLProtocol
- 作用
- 忽略网络请求使用本地缓存
- 重定向网络请求
- 改变request的请求头
- 使用
-
子类
-
实现方法
canInitWithRequest:(NSURLRequest *)request + (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request - (void)startLoading - (void)stopLoading + (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request
-
拦截 你需要拦截的地址
-
startLoading 进行修改
self.client URLProtocol
-
- 注意还有一个死循环
HTTPCookie
-
cookie获取
[NSHTTPCookieStorage sharedHTTPCookieStorage].cookies
-
cookie删除
[[NSHTTPCookieStorage sharedHTTPCookieStorage] deleteCookie:cookice];
-
cookie添加
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:newcookie]; request.allHTTPHeaderFields = headerDict
-
WK的cookie特殊性
//第一次进行JS注入 [contoller addUserScript:[[WKCookieManager shareManager] futhureCookieScript]]; [self cookieAppendRequest] //防止跨域丢失 cookie[[WKCookieManager shareManager] fixNewRequestCookieWithRequest:navigationAction.request];
-
代码部分
//获取Cookie NSHTTPCookieStorage *storages = [NSHTTPCookieStorage sharedHTTPCookieStorage]; for (NSHTTPCookie *cookie in [storages cookies]) { NSLog(@"%@",cookie); } //设置Cookie - (void)setCookieWithDomain:(NSString*)domainValue sessionName:(NSString *)name sessionValue:(NSString *)value expiresDate:(NSDate *)date{ NSURL *url = [NSURL URLWithString:domainValue]; NSString *domain = [url host]; //创建字典存储cookie的属性值 NSMutableDictionary *cookieProperties = [NSMutableDictionary dictionary]; //设置cookie名 [cookieProperties setObject:name forKey:NSHTTPCookieName]; //设置cookie值 [cookieProperties setObject:value forKey:NSHTTPCookieValue]; //设置cookie域名 [cookieProperties setObject:domain forKey:NSHTTPCookieDomain]; //设置cookie路径 一般写"/" [cookieProperties setObject:@"/" forKey:NSHTTPCookiePath]; //设置cookie版本, 默认写0 [cookieProperties setObject:@"0" forKey:NSHTTPCookieVersion]; //设置cookie过期时间 if (date) { [cookieProperties setObject:date forKey:NSHTTPCookieExpires]; }else{ [cookieProperties setObject:[NSDate dateWithTimeIntervalSince1970:([[NSDate date] timeIntervalSince1970]+365*24*3600)] forKey:NSHTTPCookieExpires]; } [[NSUserDefaults standardUserDefaults] setObject:cookieProperties forKey:@"app_cookies"]; //删除原cookie, 如果存在的话 NSArray * arrayCookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]; for (NSHTTPCookie * cookice in arrayCookies) { [[NSHTTPCookieStorage sharedHTTPCookieStorage] deleteCookie:cookice]; } //使用字典初始化新的cookie NSHTTPCookie *newcookie = [NSHTTPCookie cookieWithProperties:cookieProperties]; //使用cookie管理器 存储cookie [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:newcookie]; }
- WK的cookie 退出重新进,cookie不存在
- UI存的NSHTTPCookieStorage,可以在沙盒找到文件
- WK存的WKHTTPCookieStorage,走的是Webkit内核
网络框架
- 网络请求的派发
- 请求的派发与取消
- 多服务器的切换
- 对象处理接口
- 请求结果的格式化
- 缓存处理
-
KCURLRequestGenerator
-
KCService
-
KCNetworkClient
-
KCAPIManager
-
KCCache
#import "KCURLProtocol.h" #import <objc/runtime.h> #import <UIKit/UIKit.h> #import <WebKit/WebKit.h> static NSString *const kcProtocolKey = @"kcProtocolKey"; @implementation KCURLProtocol // 这个方法是注册后,NSURLProtocol就会通过这个方法确定参数request是否需要被处理 // return : YES 需要经过这个NSURLProtocol"协议" 的处理, NO 这个 协议request不需要遵守这个NSURLProtocol"协议" // 这个方法的作用 : // -| 1, 筛选Request是否需要遵守这个NSURLRequest , // -| 2, 处理http: , https等URL + (BOOL)canInitWithRequest:(NSURLRequest *)request{ if ([NSURLProtocol propertyForKey:kcProtocolKey inRequest:request]) { return NO; } NSString *scheme = [[request URL] scheme]; NSString *absoluteString = [[request URL] absoluteString]; NSLog(@"absoluteString--%@",absoluteString); //注入 -- 拦截图片,到startLoading NSString* extension = request.URL.pathExtension; NSArray *array = @[@"png", @"jpeg", @"gif", @"jpg"]; if([array containsObject:extension]){ return YES; } if ([absoluteString isEqualToString:@"https://m.baidu.com/static/index/plus/plus_logo.png"] || [absoluteString isEqualToString:@"http://www.baidu.com"]) { return YES; } return NO; } //这个方法就是返回规范的request + (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request{ return request; } // 需要在该方法中发起一个请求,对于NSURLConnection来说,就是创建一个NSURLConnection,对于NSURLSession,就是发起一个NSURLSessionTask // 另外一点就是这个方法之后,会回调协议中的方法, - (void)startLoading{ NSLog(@"来了"); NSMutableURLRequest *request = [self.request mutableCopy]; NSString *absoluteString = [[request URL] absoluteString]; [NSURLProtocol setProperty:@(YES) forKey:kcProtocolKey inRequest:request]; NSData *data = [self getImageData]; [self.client URLProtocol:self didLoadData:data]; //重定向 // request.URL = [NSURL URLWithString:@"http://127.0.0.1:8080/pythonJson/"]; // // [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) { // // NSLog(@"startLoading == %@---%@",response,data); // // [self.client URLProtocol:self didLoadData:data]; // [self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageAllowed]; // }]; } // 这个方法是和start是对应的 一般在这个方法中,断开Connection // 另外一点就是当NSURLProtocolClient的协议方法都回调完毕后,就会开始执行这个方法了 - (void)stopLoading{ } // 这个方法主要用来判断两个请求是否是同一个请求, // 如果是,则可以使用缓存数据,通常只需要调用父类的实现即可,默认为YES,而且一般不在这里做事情 + (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b { return [super requestIsCacheEquivalent:a toRequest:b]; } #pragma mark - private - (NSData *)getImageData{ NSString *fileName = [[NSBundle mainBundle] pathForResource:@"lufei.jpg" ofType:@""]; return [NSData dataWithContentsOfFile:fileName]; } #pragma mark - 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 @[[KCURLProtocol class]]; //如果还有其他的监控protocol,也可以在这里加进去 } @end