iOS 網絡請求劫持

1、概述:

NSURLProtocol是URL loading system 中的一個重要的組成部分,它允許我們對全局的網絡請求(基於使用URLRequest)做攔截,可攔截的請求類型有NSURLConnection、NSURLSession 和 UIWebView中的請求。對於WKWebView的請求,它是無能爲力的。
成功攔截網絡請求後,有且不侷限於如下:
忽略網絡請求,直接返回自定義的Response
修改request(請求地址,認證信息等等)
爲了測試對HTTP返回內容進行mock和stub
創建本地代理服務,用於數據變化時對URL請求的更改
故意製造畸形或非法返回數據來測試程序的魯棒性
過濾請求和返回中的敏感信息
在既有協議基礎上完成對 NSURLConnection 的實現且與原邏輯不產生矛盾

2、實現

2.1需要從URLProtocol派生自己的協議類,那麼必須重寫以下四個方法

@objc class CustomURLProtocol: URLProtocol {
    
    override class func canInit(with:URLRequest) -> Bool { // 是否攔截請求,再做處理
        if let url = with.url {
            
            if with.url!.host == "your host" {
                return true
            }
        }
        
        return false
    }
    
    override class func canonicalRequest(for: URLRequest) ->URLRequest {
        return `for`
    }
    
    override func startLoading() {
        self.stopLoading()
        
    }
    
    override func stopLoading() {
        
        self.client?.urlProtocolDidFinishLoading(self)
    }
    
    override class func requestIsCacheEquivalent(_ a: URLRequest, to b: URLRequest) -> Bool {
        return true
    }
}
2.2再使用NSURLConnection或NSURLSession結合client對象處理該請求,使用client對象,將請求相關的結果返回URL loading system

以URLConnection爲例:

func connection(_ connection: NSURLConnection, didFailWithError error: Error) {
        self.client?.urlProtocol(self, didFailWithError: error)
    }
    
    func connection(_ connection: NSURLConnection, didReceive response: URLResponse) {
        self.client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed)
    }
    
    func connection(_ connection: NSURLConnection, didReceive data: Data) {
        self.client?.urlProtocol(self, didLoad: data)
    }
    
    func connectionDidFinishLoading(_ connection: NSURLConnection) {
        self.client?.urlProtocolDidFinishLoading(self)
    }

3、註冊自定義的協議名

如果你使用的是OC,可以在自定義類中的重寫+load()

+ (void)load {
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        [NSURLProtocol registerClass:self];
    });
}

如果你使用的是Swift,需要在app進行網絡請求之前完成註冊:

URLProtocol.registerClass(CustomURLProtocol.classForCoder())

詳細的Demo可以參照:

NSURLProtocol的用法



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章