OkHttp接入HttpDNS,最佳实践

DNS(Domain Name System)即域名解析系统,这个东西说对于开发者来说,应该是没有不知道的。说简单点,这个系统的作用就是将域名解析成IP地址。我们的每一次网络请求,如果是使用域名,那么就是进行域名解析。

一个优秀的域名服务应该能够满足两点要求,一个是能够正确的返回IP地址,二就是能够根据网络情况返回所请求的域名最近的服务器IP。

1478134889575.jpg

LocalDNS

一个DNS查询,会先从本地缓存查找,如果没有或者已经过期,就从DNS服务器查询,如果客户端没有主动设置DNS服务器,一般是从服务商DNS服务器上查找。这就出现了不可控。因为如果使用了IPS的LocalDNS域名服务器,那么基本都会或多或少地无法避免在有中国特色的互联网环境中遭遇到各种域名被缓存、用户跨网访问缓慢等问题。

我们先来看看普通域名服务会有什么问题:

1. 域名劫持:

一些小服务商以及小地方的服务商非常喜欢干这个事情。根据腾讯给出的数据,DNS劫持率7%,恶意劫持率2%。网速给的劫持率是10-15%。

  • 把你的域名解析到竞争对手那里,然后哭死都不知道,为什么流量下降了。
  • 在你的代码当中,插入广告或者追踪代码。这就是为什么在淘宝或者百度搜索一下东西,很快就有人联系你。
  • 下载APK文件的时候,替换你的文件,下载一个其他应用或者山寨应用。
  • 打开一个页面,先跳转到广告联盟,然后跳转到这个页面。无缘无故多花广告钱,以及对运营的误导。

2.智能DNS策略失效

智能DNS,就是为了调度用户访问策略,但是这些因素会导致智能DNS策略失效。

  • 小运营商,没有DNS服务器,直接调用别的服务商,导致服务商识别错误,直接跨网传输,速度大大下降。
  • 服务商多长NAT,实际IP,获得不了,结果没有就近访问。
  • 一些运营商将IP设置到开卡地,即使漫游到其他地方,结果也是没有就近访问。

目前国内大多数企业对于域名解析这块问题没有进行特殊处理,这导致了上述说的那些问题,其中域名劫持的问题相当普遍。那么有没有一种方法能够避免上述的情况呢?有,当然有。那就是使用HttpDNS。

HttpDNS

HttpDNS其实也是对DNS解析的另一种实现方式,只是将域名解析的协议由DNS协议换成了Http协议,并不复杂。使用HTTP协议向D+服务器的80端口进行请求,代替传统的DNS协议向DNS服务器的53端口进行请求,绕开了运营商的Local DNS,从而避免了使用运营商Local DNS造成的劫持和跨网问题。

接入HttpDNS也是很简单的,使用普通DNS时,客户端发送网络请求时,就直接发送出去了,有底层网络框架进行域名解析。当接入HttpDNS时,就需要自己发送域名解析的HTTP请求,当客户端拿到域名对应的IP之后,就向直接往此IP发送业务协议请求。

这样,就再也不用再考虑传统DNS解析会带来的那些问题了,因为是使用HTTP协议,所以不用担心域名劫持问题了;而且,如果选择好的DNS服务器提供商,还保证将用户引导的访问速度最快的IDC节点上。

接入HttpDNS之前

既然HttpDNS这么好,那么咱们就开始接入吧。不过先慢着,在接入时还需要考虑一个问题:HttpDNS服务器用哪家的呢?

选择服务商

目前,比较出名的HttpDNS服务提供商有两家(腾讯和阿里):

因为第一家有免费版本可供使用,所以我们就使用 DNSPOD 来演示如何接入HttpDNS了。

选择接入SDK

既然已经选择了 DNSPOD ,那么我们进入其网站的接入页面,能够看到其收费信息和接入指南。一般来说一个服务提供商应该会想所有客户端提供响应的SDK以方便使用,不过这个 DNSPOD 没有,他只提供了一个C语言版本,如果是企业用户,他会给提供一个定制的SDK以供使用,对于免费用户,如果不用这个C语言版本,还有一个选择,那就是开源的第三方SDK:

上面的SDK大同小异用哪个都差不多,此处我们就拿七牛的安卓版本来演示接入。

接入HttpDNS

现在我们已经做好了接入前的大量准备,那么从现在开始就可以进入代码部分了,这也是最重点的部分了。

首先,为了方便演示,我们使用 Android Studio 新建立了一个空的工程;然后,我们需要引入两个库,一个是Okhttp,另一个就是七牛的D+开源SDK了:

compile 'com.qiniu:happy-dns:0.2.13'
compile 'com.squareup.okhttp3:okhttp:3.9.0'

第一个是七牛的库,这个库在github上没有说明自己的gradle依赖,但是可以查到,这个库的名字起的还是挺欢乐的。
第二个库就是大名鼎鼎的OkHttp了,至于为什么会用这个库,有两方面原因:一是该库使用人数巨大;二是使用其设置DNS解析服务是相当方便。

在构造OkHttpCient时,我们可以通过方法OkHttpClient.Builder.dns(httpDns)来设置该对象使用的DNS解析服务,这样我们就可以自定义HttpDNS域名解析了。

下面需要按照OkHttp的要求自定义DNS解析了,具体的就是需要实现Dns接口。下面的代码是我封装的一个Dns实现类:

public class HttpDns implements Dns {

    private DnsManager dnsManager;

    public HttpDns() {
        IResolver[] resolvers = new IResolver[1];
        try {
            resolvers[0] = new Resolver(getByName("119.29.29.29"));
            dnsManager = new DnsManager(NetworkInfo.normal, resolvers);
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
    }

    @Override
    public List<InetAddress> lookup(String hostname) throws UnknownHostException {
        if (dnsManager == null)  //当构造失败时使用默认解析方式
            return Dns.SYSTEM.lookup(hostname);

        try {
            String[] ips = dnsManager.query(hostname);  //获取HttpDNS解析结果
            if (ips == null || ips.length == 0) {
                return Dns.SYSTEM.lookup(hostname);
            }

            List<InetAddress> result = new ArrayList<>();
            for (String ip : ips) {  //将ip地址数组转换成所需要的对象列表
                result.addAll(Arrays.asList(getAllByName(ip)));
            }
            return result;
        } catch (IOException e) {
            e.printStackTrace();
        }
        //当有异常发生时,使用默认解析
        return Dns.SYSTEM.lookup(hostname);
    }
}

有了上面的Dns实现类,下面就是要构造出一个使用这个域名解析方式的OkHttpClient对象:

OkHttpClient okHttpClient = new OkHttpClient.Builder().dns(new HttpDns()).build();

那么接下来我们使用这个okHttpClient进行网络请求时,使用的域名解析就会从默认的域名解析转换为HttpDNS域名解析了。是不是很容易,这也是OkHttp的优势之一:便于定制。

这样就完成了接入HttpDNS。

得力于OkHttp的优势和七牛提供的库,我并没有感觉很麻烦。之前我看到有的博客上写的使用拦截器的方式接入HttpDNS,虽然也能用,但是我个人感觉并不是很好。所以拦截器方式的代码就不贴出来了。OkHttp的拦截器很强大,能做很多事,处理DNS当然也不在话下,不过拦截器不是做这个事情的,更何况OkHttp提供了对于DNS的设置。所以还是建议使用这种方式接入。

8a7e5591-e97b-4676-b095-fcb1ab088ea1.jpg
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,657评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,662评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,143评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,732评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,837评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,036评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,126评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,868评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,315评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,641评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,773评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,859评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,584评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,676评论 2 351

推荐阅读更多精彩内容

  • 看了Joy一篇关于网络部分优化的文章,总结一下,方便以后查阅使用 目前客户端存在的网络问题主要有下面几方面: 1....
    SpursGo阅读 3,612评论 1 5
  • 背景 前段时间在处理iOS端的HTTPDNS相关SDK,在接入和测试环节发现大家对HTTP的整体请求流程包括HTT...
    茉莉儿阅读 3,097评论 5 16
  • DNS 是什么 DNS (Domain Name System), 也叫网域名称系统,是互联网的一项服务。它实质上...
    interstellar多米诺阅读 2,802评论 0 6
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,637评论 18 139
  • 《既见君子》是我在公众号“不止读书”那儿看到的推荐,它说如果想看懂古诗可以从某几本书开始接触,我看了推荐语之后很高...
    飞鱼kiwi阅读 903评论 0 0