【iOS开发】NSURLProtocol的使用
参考文章:
iOS开发之--- NSURLProtocol
NSURLProtocol
NSURLProtocol 是一个抽象类,它是一个抽象类,你可以通过子类化来定义新的或已经存在的URL加载行为。
利用这个类,可以用来实现:
- 通过让网页来请求自定义的特定的url,来实现H5与原生应用的交互
- 对发出请求的header进行格式化
- 创建本地代理服务,用于数据变化时对URL请求进行更改
...
如何使用
1、注册你的NSURLProtocol 子类
当请求被加载时,系统会向每一个注册过的protocol询问:“Hey你能控制这个请求吗?”第一个通过 +canInitWithRequest: 回答为 YES 的protocol就会控制该请求。URL protocol会被以注册顺序的反序访问,所以当在-application:didFinishLoadingWithOptions:
方法中调用 [NSURLProtocol registerClass:[MyURLProtocol class]];
时,你自己写的protocol比其他内建的protocol拥有更高的优先级。
2、实现+canInitWithRequest:
方法
这个方法主要是说明你是否打算处理这个request,如果是返回yes,否则返回NO。
tips: 因为我们处理时的思路一般先拦截请求,然后对请求进行一定的修改或处理,然后利用NSURLSesson或者NSURLConnection来真正的发送请求。这时就没必要再对其进行处理,不然会造成死循环。所以,要有一个标示来标示这个request是否已经被我们处理过了。一般使用的方法是在- (void)startLoading
方法里用
[NSURLProtocol setProperty:@YES forKey:URLProtocolHandledKey inRequest:mutableReqeust];方法来为这个request加一个property,在
+canInitWithRequest:`方法里判断有没有这个property。
如下:
+ (BOOL)canInitWithRequest:(NSURLRequest *)request
{
//只处理host里面包含@“baidu”的请求
NSString *urlStr = [request URL].host;
if ([urlStr containsString:@"www.google.com"]) {
if ([NSURLProtocol propertyForKey:URLProtocolHandledKey inRequest:request]) {
return NO;
}
return YES;
}
return NO;
}
3、实现 +canonicalRequestForRequest
这个方法返回一个请求,即是我们修改过的请求。
+ (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 = @"www.baidu.com";
NSString *urlString = [originUrlString stringByReplacingCharactersInRange:hostRange withString:ip];
NSURL *url = [NSURL URLWithString:urlString];
request.URL = url;
return request;
}
4、实现开始、停止请求方法
- (void)startLoading
{
NSMutableURLRequest *mutableReqeust = [[self request] mutableCopy];
//标示改request已经处理过了,防止无限循环
[NSURLProtocol setProperty:@YES forKey:URLProtocolHandledKey inRequest:mutableReqeust];
self.connection = [NSURLConnection connectionWithRequest:mutableReqeust delegate:self];
}
//停止请求
- (void)stopLoading
{
[self.connection cancel];
}
5、将请求的结果通过client返回给URL Loading System
因为这里我作的是NSURLConnect来做的请求,所以在NSURLConnectDataDelegate 方法里面来做这件事,如果你是你的NSURLSession,方法类似。
- (nullable NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(nullable NSURLResponse *)response
{
return request;
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageAllowed];
}
- (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];
}
一个简单的Demo
上面即是NSURLProtocol 使用的介绍。
ps:在研究这个问题的时候,看到好多地方提到URL Loading System,现在网络请求只是会用,具体的实现还不是很懂,后面要找时间研究一下。