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的用法



展开阅读全文

没有更多推荐了,返回首页