在Okhttp中使用HTTPDNS
背景
用户经常在国外使用App,国外的网络环境更加复杂,经常会出现UnknownHostException的异常,无法解析DNS。
解决方案
当遇到该异常时就需要自己去解析DNS。常用的自己解析DNS的方式有两种
1.自己拿到IP后替换域名(App老的方式)
比如使用dnsjava拿到IP后需要:
- 对请求的域名进行替换
- 对Header中的Host进行替换
- 对Cookie中的domain进行替换
- Https下证书校验问题
- .……
使用起来比较麻烦,问题较多。
2.使用Okhttp自定义DNS功能
目前刚把App从android-async-http切换到OKhttp。(PS:花了一周多时间,改到吐血),可以直接使用Okhttp自定义dns功能。
DNS的解析方式选择了HTTPDNS,HTTPDNS直接使用 HTTP协议去查询DNS,避开了传统UDP方式DNS的DNS劫持,不准确等弊端。
详见:【鹅厂网事】全局精确流量调度新思路-HttpDNS服务详解
3.Okhttp自定义DNS
HTTPDNS选择了DNSpod和Google Public DNS两家。
在国外采用Google Public DNS
在国内采用DNSpod
实现方式如下:
public class OkDns implements Dns {
private String mIps;
private long mLastDnsTime;
private static final long DNS_TTL = 600 * 1000;//自定义DNS缓存时间
@Override
public List<InetAddress> lookup(String hostname) throws UnknownHostException {
try {
List<InetAddress> list = Dns.SYSTEM.lookup(hostname);
return list;
} catch (Exception e) {
if (System.currentTimeMillis() - mLastDnsTime > DNS_TTL) {//超过ttl 时间就重新请求dns
mIps = null;
}
if (TextUtils.isEmpty(mIps)) {
mIps = HttpDns.getInstance().getIp(hostname);
mLastDnsTime = System.currentTimeMillis();
}
if (!TextUtils.isEmpty(mIps)) {
return Arrays.asList(InetAddress.getAllByName(mIps));
} else {
return Dns.SYSTEM.lookup(hostname);
}
}
}
}
okHttpClient = new OkHttpClient.Builder().dns(new OkDns())
4.注意
代码中没有默认采用HTTPDNS的方式,当出错后才会使用HTTPDNS。代码只为说明,非实际代码。