iOS端網(wǎng)絡(luò)攔截技術(shù)
NSURLProtocol
NSURLProtocol是URL Loading System的重要組成部分,能夠攔截?cái)r截所有基于URL Loading System的網(wǎng)絡(luò)請(qǐng)求撤逢。
可以攔截的網(wǎng)絡(luò)請(qǐng)求包括NSURLSession凯正,NSURLConnection以及UIWebVIew。
基于CFNetwork的網(wǎng)絡(luò)請(qǐng)求慨畸,以及WKWebView的請(qǐng)求是無(wú)法攔截的。
代碼不夠完善Demo地址--https://github.com/softwarefaith/JiOSDNS
如何使用NSURLProtocol
NSURLProtocol是一個(gè)抽象類骂倘。創(chuàng)建他的一個(gè)子類:
@interface AppDNSInterceptor : NSURLProtocol
分為五個(gè)步驟:
注冊(cè) -> 攔截 -> 轉(zhuǎn)發(fā) -> 回調(diào) -> 完結(jié)
1.注冊(cè)
對(duì)于基于NSURLConnection或者使用[NSURLSession sharedSession]創(chuàng)建的網(wǎng)絡(luò)請(qǐng)求睡陪,調(diào)用registerClass方法即可。
[NSURLProtocol registerClass:[NSClassFromString(@"AppDNSInterceptor") class]];
對(duì)于基于NSURLSession的網(wǎng)絡(luò)請(qǐng)求庭敦,需要通過(guò)配置NSURLSessionConfiguration對(duì)象的protocolClasses屬性疼进。
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
sessionConfiguration.protocolClasses = @[[NSClassFromString(@"AppDNSInterceptor") class]];
2.攔截
是否要處理對(duì)應(yīng)的請(qǐng)求。由于網(wǎng)頁(yè)存在動(dòng)態(tài)鏈接的可能性秧廉,簡(jiǎn)單的返回YES可能會(huì)創(chuàng)建大量的NSURLProtocol對(duì)象伞广,因此我們需要保證每個(gè)請(qǐng)求能且僅能被返回一次YES.
+(BOOL)canInitWithRequest:(NSURLRequest *)request {}
+(BOOL)canInitWithTask:(NSURLSessionTask *)task { return [self canInitWithRequest:task.currentRequest];}
是否要對(duì)請(qǐng)求進(jìn)行重定向拣帽,或者修改請(qǐng)求頭、域名等關(guān)鍵信息嚼锄。返回一個(gè)新的NSURLRequest對(duì)象來(lái)定制業(yè)務(wù)
+(NSURLRequest *)canonicalRequestForRequest: (NSURLRequest *)request {
//這里截取重定向 做定制化服務(wù):比如修改頭部信息 ,dns映射ip等操作
NSMutableURLRequest *mutableRequest = [request mutableCopy];
return mutableRequest;
}
3.轉(zhuǎn)發(fā)
-(instancetype)initWithRequest:(NSURLRequest *)request cachedResponse:(NSCachedURLResponse *)cachedResponse client:(id<NSURLProtocolClient>)client {
AppDNSInterceptor *interceptor = [super initWithRequest:request cachedResponse:nil client:client];
return interceptor;}
-(void)startLoading {
NSMutableURLRequest * request = self.request.mutableCopy;
// //給我們處理過(guò)的請(qǐng)求設(shè)置一個(gè)標(biāo)識(shí)符, 防止無(wú)限循環(huán),
[NSURLProtocol setProperty: @YES forKey: kAppDNSInterceptorKey inRequest: request];
self.connection = [NSURLConnection connectionWithRequest: request delegate: self];}
4.注回調(diào)
當(dāng)網(wǎng)絡(luò)收到請(qǐng)求返回時(shí),還需要在將返回值給原來(lái)網(wǎng)絡(luò)請(qǐng)求
-(void)URLProtocol:(NSURLProtocol *)protocol wasRedirectedToRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse;
-(void)URLProtocol:(NSURLProtocol *)protocol cachedResponseIsValid:(NSCachedURLResponse *)cachedResponse;
-(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 didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
-(void)URLProtocol:(NSURLProtocol *)protocol didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
5.完結(jié)
- (void)stopLoading {
[self.managerSession cancel];
self.managerSession = nil;}
代碼不夠完善Demo地址--https://github.com/softwarefaith/JiOSDNS