本文介绍了iOS NSURLProtocol的具体使用方法详解,分享给大家,具体如下:
NSURLProtocol定义
这两天在优化项目,无意间看到了NSURLProtocol,学习一下顺便总结下来。
NSURLProtocol也是苹果众多黑魔法中的一种,能够让你去重新定义苹果的URL加载系统 (URL Loading System)的行为,URL Loading System里有许多类用于处理URL请求,比如NSURL,NSURLRequest,NSURLConnection和NSURLSession等,当URL Loading System使用NSURLRequest去获取资源的时候,它会创建一个NSURLProtocol子类的实例,NSURLProtocol看起来像是一个协议,但其实这是一个类,而且必须使用该类的子类,并且需要被注册。
NSURLProtocol使用范围
只要是使用NSURLConnection或者 NSURLSession实现的,你都可以通过NSURLProtocol做一些自定义的操作。
1、自定义请求和响应
2、网络的缓存处理(H5离线包 和 网络图片缓存)
3、重定向网络请求
4、为测试提供数据Mocking功能,在没有网络的情况下使用本地数据返回。
5、过滤掉一些非法请求
6、快速进行测试环境的切换
7、拦截图片加载请求,转为从本地文件加载
8、可以拦截UIWebView,基于系统的NSURLConnection或者NSURLSession进行封装的网络请求。目前WKWebView无法被NSURLProtocol拦截。
9、当有多个自定义NSURLProtocol注册到系统中的话,会按照他们注册的反向顺序依次调用URL加载流程。当其中有一个NSURLProtocol拦截到请求的话,后续的NSURLProtocol就无法拦截到该请求。
NSURLProtocol自定义
1
2
3
4
5
|
#import <Foundation/Foundation.h> @interface CustomURLProtocol : NSURLProtocol @end |
要实现下面的方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
+ canInitWithRequest: //抽象方法,子类给出是否能相应该请求。如果响应YES,说明自己的CustomURLProtocol实现该请求。 + canonicalRequestForRequest: //抽象方法,重写该方法,可以对请求进行修改,例如添加新的头部信息,修改,修改url等,返回修改后的请求。 + requestIsCacheEquivalent:toRequest: //看都是缓存了 - startLoading: //开始下载,需要在该方法中发起一个请求,对于NSURLConnection来说,就是创建一个NSURLConnection,对于NSURLSession,就是发起一个NSURLSessionTask 。一般下载前需要设置该请求正在进行下载,防止多次下载的情况发生 - stopLoading: //停止相应请求,清空请求Connection 或 Task |
使用自定义NSURLProtocol类
1.在单个的UIViewController中使用
1
2
3
4
5
6
7
8
|
//导入自定义NSURLProtocol类 #import "CustomURLProtocol.h" //在ViewDidLoad中添加拦截网络请求的代码 //注册网络请求拦截 [NSURLProtocol registerClass:[CustomURLProtocol class ]]; //在ViewWillDisappear中添加取消网络拦截的代码 //取消注册网络请求拦截 [NSURLProtocol unregisterClass:[CustomURLProtocol class ]]; |
2.拦截整个App中所有的网络请求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
//直接在AppDelegate中的didFinishLaunchingWithOptions注册网络拦截代码 //注册Protocol [NSURLProtocol registerClass:[CustomURLProtocol class ]]; NSURLProtocol使用实例 #define URLProtocolHandledKey @"URLProtocolHandledKey" + ( BOOL )canInitWithRequest:(NSURLRequest *)request{ //只处理http和https请求 NSString *scheme = [[request URL] scheme]; if ( ([scheme caseInsensitiveCompare:@ "http" ] == NSOrderedSame || [scheme caseInsensitiveCompare:@ "https" ] == NSOrderedSame)){ //看看是否已经处理过了,防止无限循环 if ([NSURLProtocol propertyForKey:URLProtocolHandledKey inRequest:request]) { return NO; } return YES; } return NO; } + (NSURLRequest *) canonicalRequestForRequest:(NSURLRequest *)request { /** 可以在此处添加头等信息 */ NSMutableURLRequest *mutableReqeust = [request mutableCopy]; mutableReqeust = [self redirectHostInRequset:mutableReqeust]; return mutableReqeust; } +(NSMutableURLRequest*)redirectHostInRequset:(NSMutableURLRequest*)request{ if ([request.URL host].length == 0) { return request; } NSString *originUrlString = [request.URL absoluteString]; NSString *originHostString = [request.URL host]; NSRange hostRange = [originUrlString rangeOfString:originHostString]; if (hostRange.location == NSNotFound) { return request; } //定向薄荷喵到主页 NSString *ip = @ "bohemiao.com" ; // 替换域名 NSString *urlString = [originUrlString stringByReplacingCharactersInRange:hostRange withString:ip]; NSURL *url = [NSURL URLWithString:urlString]; request.URL = url; return request; } + ( BOOL )requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b{ return [super requestIsCacheEquivalent:a toRequest:b]; } - ( void )startLoading{ NSMutableURLRequest *mutableReqeust = [[self request] mutableCopy]; //标示该request已经处理过了,防止无限循环 [NSURLProtocol setProperty:@YES forKey:URLProtocolHandledKey inRequest:mutableReqeust]; self.connection = [NSURLConnection connectionWithRequest:mutableReqeust delegate:self]; //使用NSURLSession也是一样的 } - ( void )stopLoading{ [self.connection cancel]; } - ( void ) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { [self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; } - ( void ) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { [self.client URLProtocol:self didLoadData:data]; } - ( void ) connectionDidFinishLoading:(NSURLConnection *)connection { [self.client URLProtocolDidFinishLoading:self]; } - ( void )connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { [self.client URLProtocol:self didFailWithError:error]; } |
上面用到的一些NSURLProtocolClient方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
@protocol NSURLProtocolClient <NSObject> //请求重定向 - ( void )URLProtocol:(NSURLProtocol *)protocol wasRedirectedToRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse; // 响应缓存是否合法 - ( void )URLProtocol:(NSURLProtocol *)protocol cachedResponseIsValid:(NSCachedURLResponse *)cachedResponse; //刚接收到Response信息 - ( void )URLProtocol:(NSURLProtocol *)protocol didReceiveResponse:(NSURLResponse *)response cacheStoragePolicy:(NSURLCacheStoragePolicy)policy; //数据加载成功 - ( void )URLProtocol:(NSURLProtocol *)protocol didLoadData:(NSData *)data; //数据完成加载 - ( void )URLProtocolDidFinishLoading:(NSURLProtocol *)protocol; //数据加载失败 - ( void )URLProtocol:(NSURLProtocol *)protocol didFailWithError:(NSError *)error; //为指定的请求启动验证 - ( void )URLProtocol:(NSURLProtocol *)protocol didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge; //为指定的请求取消验证 - ( void )URLProtocol:(NSURLProtocol *)protocol didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge; @end |
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://blog.duicode.com/2551.html?utm_source=tuicool&utm_medium=referral