NSURLProtocol -- DNS劫持和Web资源本地化

什么是DNS劫持

DNS劫持就是通过劫持了DNS服务器,通过某些手段取得某域名的解析记录控制权,进而修改此域名的解析结果,导致对该域名的访问由原IP地址转入到修改后的指定IP,其结果就是对特定的网址不能访问或访问的是假网址,从而实现窃取资料或者破坏原有正常服务的目的。
 常见的DNS劫持现象网络运营商向网页中注入了Javascript代码,甚至直接将我们的网页请求转发到他们自己的广告页面或者通过自己的DNS服务器将用户请求的域名指向到非法地址

如何解决DNS被劫持

全站使用HTTPS协议,或者采用HttpDNS,通过HTTP向自建的DNS服务器或者安全的DNS服务器发送域名解析请求,然后根据解析结果设置客户端的Host指向,从而绕过网络运营商的DNS解析服务。

本文的解决方案

客户端对WebView的html请求进行DNS解析。优先使用阿里、腾讯、114等公共安全的DNS服务器解析客户端的所有指定域名的http请求。相对来讲我们自己的服务域名变化较少,对此我们做了一个白名单,把凡是访问包含我们公司域名的请求都必须通过白名单的解析和DNS验证。从而杜绝被劫持的情况出现,这时候NSURLProtocol就派上用场了。

NSURLProtocol

这是一个抽象类,所以在oc中只能通过继承来重写父类的方法。

然后在AppDelegate的 application:didFinishLaunchingWithOptions: 方法或者程序首次请求网络数据之前去注册这个NSURLProtocol的子类

注册了自定义的urlProtocol子类后,之后每一个http请求都会先经过该类过滤并且通过+canInitWithRequest:这个方法返回一个布尔值告诉系统该请求是否需要处理,返回Yes才能进行后续处理。

+canonicalRequestForRequest:这个父类的抽象方法子类必须实现。

以下是官方对这个方法的解释。当我们想对某个请求添加请求头或者返回新的请求时,可以在这个方法里自定义然后返回,一般情况下直接返回参数里的NSURLRequest实例即可。

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.

+requestIsCacheEquivalent:toRquest:这个方法能够判断当拦截URL相同时是否使用缓存数据,以下例子是直接返回父类实现。

-startLoading-stopLoading两个方法分别告诉NSURLProtocol实现开始和取消请求的处理。

由于我们在-startLoading中新建了一个NSURLConnection实例,因此要实现NSURLConnectionDelegate的委托方法。

至此,通过NSURLProtocol和QNDnsManager(七牛DNS解析开源库)可以解决DNS劫持问题。但是NSURLProtocol还有更多的用途,以下是本文第二个内容:webView上web请求的资源本地化。

Web资源本地化

这里只举一个简单的示例,同样是在上述NSURLProtocol的子类的-startLoading方法里

参考链接