OKHttp 如何支持 HttpDns

 使用 HttpDns传统DNS 不同的是,HttpDns 是使用 Http协议去进行 dns 解析请求,将服务器返回的结果,也就是域名对应的服务器ip 作为我们发起请求的地址,替换使用域名

LocalDNS劫持: 由于HttpDNS是通过ip直接请求http获取服务器A记录地址,不存在向本地运营商询问domain解析过程,所以从根本避免了劫持问题。 (对于http内容tcp/ip层劫持,可以使用验证因子或者数据加密等方式来保证传输数据的可信度)
平均访问延迟下降: 由于是ip直接访问省掉了一次domain解析过程,(即使系统有缓存速度也会稍快一些‘毫秒级’)通过智能算法排序后找到最快节点进行访问。
用户连接失败率下降: 通过算法降低以往失败率过高的服务器排序,通过时间近期访问过的数据提高服务器排序,通过历史访问成功记录提高服务器排序。如果ip(a)访问错误,在下一次返回ip(b)或者ip(c) 排序后的记录。(LocalDNS很可能在一个ttl时间内(或多个ttl)都是返回记录

使用OkHttp 简单配置 HttpDns服务

方式一

在 **HttpInterceptor** 中对 host域名进行ip的替换
//工具类
public class HttpDNSUtil {
    /**
     * 转换url 主机头为ip地址
     *
     * @param url  原url
     * @param host 主机头
     * @param ip   服务器ip
     * @return
     */
    public static String getIpUrl(String url, String host, String ip) {
        if (url == null) {
            Log.e("TAG", "URL NULL");
        }
        if (host == null) {
            Log.e("TAG", "host NULL");
        }
        if (ip == null) {
            Log.e("TAG", "ip NULL");
        }
        if (url == null || host == null || ip == null) return url;
        String ipUrl = url.replaceFirst(host, ip);
        return ipUrl;
    }
    /**
     * 根据url获得ip,此方法只是最简单的模拟,实际情况很复杂,需要做缓存处理
     *
     * @param host
     * @return
     */
    public static String getIPByHost(String host) {
        HttpUrl httpUrl = new HttpUrl.Builder()
                .scheme("http")
                .host("203.107.1.1")
                .addPathSegment("d")
                .addQueryParameter("host", host)
                .build();
        //与我们正式请求独立,所以这里新建一个OkHttpClient
        OkHttpClient okHttpClient = new OkHttpClient();
        Request request = new Request.Builder()
                .url(httpUrl)
                .get()
                .build();
        try {
            String result = null;
            /**
             * 子线程中同步去获取
             */
            Response response = okHttpClient.newCall(request).execute();
            if (response.isSuccessful()) {
                String body = response.body().string();
                JSONObject jsonObject = new JSONObject(body);
                JSONArray ips = jsonObject.optJSONArray("ips");
                if (ips != null) {
                    result = ips.optString(0);
                }
            }
            return result;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return null;
    }
}
//拦截器
public class HttpDNSInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request originRequest = chain.request();
        HttpUrl httpUrl = originRequest.url();

        String url = httpUrl.toString();
        String host = httpUrl.host();
        Log.e("HttpDNS", "origin url:" + url);
        Log.e("HttpDNS", "origin host:" + host);

        String hostIP = HttpDNSUtil.getIPByHost(host);

        Request.Builder builder = originRequest.newBuilder();
        if (hostIP != null) {
            builder.url(HttpDNSUtil.getIpUrl(url, host, hostIP));
            builder.header("host", hostIP);
            Log.e("HttpDNS", "the host has replaced with ip " + hostIP);
        } else {
            Log.e("HttpDNS", "can't get the ip , can't replace the host");
        }

        Request newRequest = builder.build();
        Log.e("HttpDNS", "newUrl:" + newRequest.url());
        Response newResponse = chain.proceed(newRequest);
        return newResponse;
    }
}
// 为okHttpClient 添加拦截器
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.interceptors().add(new HttpDNSInterceptor());
OkHttpClient okHttpClient = builder.build();

方式二

  使用 OkHttpClient 的 setDns(Dns)方法
(腾讯有免费的 HttpDns 服务,可以去它的网站查看相关资料)

//重载 Dns的lookup 方法,根据host 返回 InetAddress
 @Override
    public List<InetAddress> lookup(String host) throws UnknownHostException {

        if(host == null) {
            throw new UnknownHostException("host == null");
        } else {
            // HttpDNS 是自己编写的一个 帮助类,根据host 返回ips
            String[] ips = HttpDNS.getAddressesByName(host);
            if(Utils.isArrayEmpty(ips)) {
                return Arrays.asList(InetAddress.getAllByName(host));
            }

            compareWithHistory(host, ips);

            List<InetAddress> addresses = new ArrayList<InetAddress>();
            for (int i = 0; i < ips.length; i++) {
                addresses.add(InetAddress.getByName(ips[i]));
            }
            return addresses;
        }
    }
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

卓修武

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值