對CustomHTTPProtocol的理解

Auditore發表於2017-12-29

整理了下關於CustomHTTPProtocol的知識,順帶畫了張流程圖,方便自己梳理。

CustomHTTPProtocol.m流程 (3).png

1.初始化請求canInitWithRequest 不是所有請求都要經過定製的協議來走,我們自己定製實現的Protocol可以根據不同條件篩選請求,同時對請求做更完整的包裝定義。 在NSURLProtocol.h的interface定義中,以下兩個方法是比較關鍵的:

  • canInitWithRequest:
  • (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request; ​

使用canInitWithRequest:我們可以篩選出可以使用當前協議的request,其它的忽略掉,直接走其它協議或者預設實現。

2.規範化request canonicalRequestForRequest 這個方法用於過濾請求,通過shouldAccept來判斷是否接受該request,例如由於只接受http和https所以不是這兩者的請求則不接受,以及判斷是否被標記,被標記意味著已經經過本類處理,則本類不再處理。

3.對request進行打標記flag 很多情況下,具體的通訊實現最終可能還是要採用系統自身提供的預設實現,但卻又需要我們做過濾包裝。通常的辦法是我們對request按需求場景做特定處理,最後返給系統,走預設實現。 但這樣這個request很有可能會再次進入這個protocol,所以通常在對request進行完第一次處理後,打個標,下次進入canInitWithRequest時直接過濾掉。 所謂的打標就會涉及到對request的屬性操作,需要如下方法:

  • (id)propertyForKey:(NSString *)key inRequest:(NSURLRequest *)request;
  • (void)setProperty:(id)value forKey:(NSString *)key inRequest:(NSMutableURLRequest *)request;
  • (void)removePropertyForKey:(NSString *)key inRequest:(NSMutableURLRequest *)request; ​

大家可能會想,這樣的方法不應該是NSURLRequest類的麼?或者是Category? 是的,看起來是可以這樣的。但大家注意到這是NSURLProtocol的類(+)方法,也就是說這裡的API是以工具方法提供的。

4.協議內容實現和與client互動 下面說實現協議最重要的部分,做一個Protocol總要有實現的。重寫如下兩個方法,在方法內部實現定製

  • (void)startLoading;
  • (void)stopLoading; ​ 在實現這兩個方法時,通過URL Loading System和上層打交道是一定要有的。這就是NSURLProtocol.h中的另一部分內容——NSURLProtocolClient。NSURLProtocolClient是一個Objective-C的protocol,定義了一些方法。我們在實現startLoading/stopLoading時,我們只要在有必要和系統互動時拿到self.client物件呼叫就好,client會由上下文例項化好供我們使用。
  1. 對請求代理回撥進行處理 在代理回撥中處理authentication challenge,請參考文章:iOS-HTTPS

參考文獻: 1.iOS 開發中使用 NSURLProtocol 攔截 HTTP 請求 2.定製實現NSURLProtocol 3.對蘋果CustomHTTPProtocol的理解 4.NSURLProtocol和NSRunLoop的那些坑 5.iOS-HTTPS