NSURLProtocol

NSURLProtocol

NSURLProtocol 是 iOS里面的URL Loading System的一部分,URL loading system 原生已經(jīng)支持了 http,https,file,ftp,data 這些常見協(xié)議,當(dāng)然也允許我們定義自己的 protocol 去擴(kuò)展,或者定義自己的協(xié)議。當(dāng)URL loading system通過 NSURLRequest 對象進(jìn)行請求時(shí),將會自動創(chuàng)建 NSURLProtocol (是一個(gè)對象)的實(shí)例(可以是自定義的),這樣我們就有機(jī)會對該請求進(jìn)行處理。

  • 可以攔截 UIWebViewWKWebView (需額外處理),基于系統(tǒng)的 NSURLConnection 或者 NSURLSession 進(jìn)行封裝的網(wǎng)絡(luò)請求。
  • 忽略網(wǎng)絡(luò)請求,直接返回自定義的 Response
  • 修改 request (請求地址,認(rèn)證信息等等)
  • 返回?cái)?shù)據(jù)攔截

URL Loading System不清楚的,可以看看下面這張圖,看看里面有哪些類:

image.png



使用NSURLProtocol的主要可以分為5個(gè)步驟:
注冊—>攔截—>轉(zhuǎn)發(fā)—>回調(diào)—>結(jié)束

NSURLProtocol的創(chuàng)建

@interface CFTHTTPProtocol : NSURLProtocol

@end
  • 首先是繼承系統(tǒng)的 NSURLProtocol :
[NSURLProtocol registerClass:[CFTHTTPProtocol class]];
  • 然后在 application:didFinishLaunchingWithOptions: 方法中注冊,一旦注冊完畢后,它就有機(jī)會來處理所有交付給URL Loading system的網(wǎng)絡(luò)請求。

子類NSURLProtocol必須實(shí)現(xiàn)的方法

+ (BOOL)canInitWithRequest:(NSURLRequest *)request;
  • 攔截,這個(gè)方法是自定義 protocol 的入口,如果不打算處理,返回NO,如果你需要對自己關(guān)注的請求進(jìn)行處理則返回YES,這樣,URL loading system將會把本次請求的操作都給了你這個(gè) protocol。

    這里有個(gè)需要注意的地方,想象一下,當(dāng)你去加載一個(gè)URL資源的時(shí)候,URL Loading System會詢問 CustomURLProtocol 是否能處理該請求,你返回YES,然后URL Loading System會創(chuàng)建一個(gè) CustomURLProtocol 實(shí)例然后調(diào)用 NSURLSession 去獲取數(shù)據(jù),然而這也會調(diào)用URL Loading System,而你在 +canInitWithRequest: 中又總是返回YES,這樣URL Loading System又會創(chuàng)建一個(gè) CustomURLProtocol 實(shí)例導(dǎo)致無限循環(huán)。我們應(yīng)該保證每個(gè)request只被處理一次,可以通過 +setProperty:forKey:inRequest: 標(biāo)示那些已經(jīng)處理過的request,然后在 +canInitWithRequest: 中查詢該request是否已經(jīng)處理過了,如果是則返回NO。
+ (NSURLRequest *) canonicalRequestForRequest:(NSURLRequest *)request
  • 這個(gè)方法主要是用來返回格式化好的 request ,如果自己沒有特殊需求的話,直接返回當(dāng)前的 request 就好了。如果你想做些其他的,比如地址重定向,或者請求頭的重新設(shè)置,你可以copy下這個(gè) request 然后進(jìn)行設(shè)置并返回一個(gè)新的 request ,這是一個(gè)抽象方法,子類必須實(shí)現(xiàn)。
+ (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b;
  • 這個(gè)方法用于判斷你的自定義reqeust是否相同,這里返回默認(rèn)實(shí)現(xiàn)即可。它的主要應(yīng)用場景是某些直接使用緩存而非再次請求網(wǎng)絡(luò)的地方。
- (void)startLoading;
- (void)stopLoading;
  • 這兩個(gè)方法主要是開始和取消相應(yīng)的request,而且需要標(biāo)示那些已經(jīng)處理過的request。

實(shí)現(xiàn)NSURLSessionDataDelegate和NSURLSessionTaskDelegate

回調(diào),如果你對你關(guān)注的請求進(jìn)行了攔截,那么你就需要通過實(shí)現(xiàn) NSURLProtocolClient 這個(gè)協(xié)議的對象將消息轉(zhuǎn)給URL loading system,也就是 NSURLProtocol 中的 client 這個(gè)對象。看看這個(gè) NSURLProtocolClient 里面的方法:

- (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;

你會發(fā)現(xiàn)和 NSURLSessionDelegate 很像,其實(shí)就是做了個(gè)轉(zhuǎn)發(fā)的操作。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容