NSURLProtocol概述
?
一、概念
NSURLProtocol也是蘋果眾多黑魔法中的一種,使用它可以輕松地重定義整個URL Loading System。當你注冊自定義NSURLProtocol后,就有機會對所有的請求進行統(tǒng)一的處理,基于這一點它可以讓你:
1.自定義請求和響應(yīng)
2.提供自定義的全局緩存支持
3.重定向網(wǎng)絡(luò)請求
4.提供HTTP Mocking (方便前期測試)
5.其他一些全局的網(wǎng)絡(luò)請求修改需求
二、如果注冊多個URLProtocol會怎么樣?
1.最后注冊的Protocol最先執(zhí)行。即倒序遍歷。
2.如果其中一個Protocol的canInitWithRequest方法返回了YES,則后續(xù)的Protocol不再執(zhí)行;否則會一直遍歷,直到找到能處理此請求的Protocol。
三、使用方法
1.繼承NSURLPorotocl,并注冊你的NSURLProtocol
當NSURLConnection準備發(fā)起請求時,它會遍歷所有已注冊的NSURLProtocol,詢問它們能否處理當前請求。所以你需要盡早注冊這個Protocol。
2.對于NSURLSession的請求,注冊NSURLProtocol的方式稍有不同,是通過NSURLSessionConfiguration注冊的:
3. 請求結(jié)束后注銷NSURLProtocol
[NSURLProtocol unregisterClass:[MyURLProtocol class]];4.實現(xiàn)NSURLProtocol的相關(guān)方法
(1)當遍歷到我們自定義的NSURLProtocol時,系統(tǒng)先會調(diào)用canInitWithRequest:這個方法。顧名思義,這是整個流程的入口,只有這個方法返回YES我們才能夠繼續(xù)后續(xù)的處理。我們可以在這個方法的實現(xiàn)里面進行請求的過濾,篩選出需要進行處理的請求。
?
(2)當篩選出需要處理的請求后,就可以進行后續(xù)的處理,需要至少實現(xiàn)如下4個方法
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {return request; }+ (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b {return [super requestIsCacheEquivalent:a toRequest:b]; }- (void)startLoading {NSMutableURLRequest *mutableReqeust = [[self request] mutableCopy];[NSURLProtocol setProperty:@(YES) forKey:MyURLProtocolHandled inRequest:mutableReqeust];self.connection = [NSURLConnection connectionWithRequest:mutableReqeust delegate:self]; }- (void)stopLoading {[self.connection cancel];self.connection = nil; }說明:
(1)canonicalRequestForRequest: 返回規(guī)范化后的request,一般就只是返回當前request即可。
(2)requestIsCacheEquivalent:toRequest: 用于判斷你的自定義reqeust是否相同,這里返回默認實現(xiàn)即可。它的主要應(yīng)用場景是某些直接使用緩存而非再次請求網(wǎng)絡(luò)的地方。
(3)startLoading和stopLoading 實現(xiàn)請求和取消流程。
5.實現(xiàn)NSURLConnectionDelegate和NSURLConnectionDataDelegate
因為在第二步中我們接管了整個請求過程,所以需要實現(xiàn)相應(yīng)的協(xié)議并使用NSURLProtocolClient將消息回傳給URL Loading System。在我們的場景中推薦實現(xiàn)所有協(xié)議。
四、NSURLProtocol那些坑
坑1:企圖在canonicalRequestForRequest:進行request的自定義操作,導(dǎo)致各種遞歸調(diào)用導(dǎo)致連接超時。這個API的表述其實很曖昧:
It is up to each concrete protocol implementation to define what “canonical” means. A protocol should guarantee that the same input request always yields the same canonical form.
所謂的canonical form到底是什么呢?而圍觀了包括NSEtcHosts和RNCachingURLProtocol在內(nèi)的實現(xiàn),它們都是直接返回當前request。在這個方法內(nèi)進行request的修改非常容易導(dǎo)致遞歸調(diào)用(即使通過setProperty:forKey:inRequest:對請求打了標記)
坑2:沒有實現(xiàn)足夠的回調(diào)方法導(dǎo)致各種奇葩問題。如connection:willSendRequest:redirectResponse: 內(nèi)如果沒有通過[self client]回傳消息,那么需要重定向的網(wǎng)頁就會出現(xiàn)問題:host不對或者造成跨域調(diào)用導(dǎo)致資源無法加載。
坑3.崩潰報錯:
有一點蘋果說明的不是很清楚,蘋果自己實現(xiàn)CustomHTTPProtocol源碼中很好的體現(xiàn)了這一點:
NSURLProtocolClient回調(diào)動作必須跟請求的托管發(fā)送保持在一個線程、相同的Runloop,具體實現(xiàn)邏輯如下:
(1)在start方法中記錄當前線程和Runloop模式;
(2)所有對于NSURLProtocolClient的回調(diào),都在記錄的線程、以相同的Runloop模式觸發(fā),使用如下方法:
坑4:httpBody
NSURLProtocol在攔截NSURLSession的POST請求時不能獲取到Request中的HTTPBody。蘋果官方的解釋是Body是NSData類型,而且還沒有大小限制。為了性能考慮,攔截時就沒有拷貝。
?
坑5:Protocol請求攔截對證書認證方法的影響
因為URLConnection新增了證書認證方法:
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;但是NSURLProtocolClient并沒有增加對應(yīng)的回調(diào)方法,會導(dǎo)致原始請求的證書校驗代理方法不調(diào)用。
暫時無正解。有解決方案的朋友歡迎騷擾。
總結(jié)
以上是生活随笔為你收集整理的NSURLProtocol概述的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: gtx1660是什么级别的_GTX166
- 下一篇: [数据库]---nosql,非关系型数据