Android OkHttp实现HttpDns的最佳实践(非拦截器)
之前写过一篇文章 Android 使用OkHttp支持HttpDNS,该文章中使用的是OkHttp的拦截器来实现HttpDNS。在请求发出去之前,将URL中的域名替换成ip,再往Header中添加Host。这种方式有以下优点。
- 上层方便控制哪些请求使用了HttpDNS,可以做相应的容灾处理,比如ip请求失败时使用域名进行重试。
同样的也有很多缺点。
- Https场景下ip直连出现的证书校验问题
- 代理场景下的HttpDNS问题
- ip访问的时候Cookie的问题
于是,不得不寻找一种更加的解决方案,OkHttp其实暴露了一个Dns接口,默认的实现是使用系统的方法发送udp请求进行dns解析。于是,我们就可以实现一个Dns接口,解析的方式使用httpdns,将解析结果返回,接口实现之后将系统默认的Dns接口替换成我们的Dns接口。
首先,新建HttpDns类,实现Dns接口。内部维持一个系统默认的Dns对象。
public class HttpDns implements Dns {private static final Dns SYSTEM = Dns.SYSTEM;@Overridepublic List<InetAddress> lookup(String hostname) throws UnknownHostException {Log.e("HttpDns", "lookup:" + hostname);return SYSTEM.lookup(hostname);}
}
我们只需要在lookup方法中调用HttpDns的SDK去获取IP,如果获取到的ip非空,并且ttl没有过期,则使用HttpDns。完整的方法的代码如下
public class HttpDns implements Dns {private static final Dns SYSTEM = Dns.SYSTEM;@Overridepublic List<InetAddress> lookup(String hostname) throws UnknownHostException {Log.e("HttpDns", "lookup:" + hostname);String ip = DNSHelper.getIpByHost(hostname);if (ip != null && !ip.equals("")) {List<InetAddress> inetAddresses = Arrays.asList(InetAddress.getAllByName(ip));Log.e("HttpDns", "inetAddresses:" + inetAddresses);return inetAddresses;}return SYSTEM.lookup(hostname);}
}
DNSHelper类中做的就是将域名转换为ip,具体转换过程涉及到缓存,这里不展开,可以参考新浪的HTTPDNS库https://github.com/CNSRE/HTTPDNSLib
之后初始化OkHttp的时候将Dns替换为HttpDns对象。
OkHttpClient client = new OkHttpClient.Builder().dns(new HttpDns()).build();
这样,使用client对象发出去的请求都是走httpdns解析dns的,除非没有命中httpdns缓存。
这样做有什么好处呢?这样做相当于还是用域名进行访问,只不过底层的dns解析换成了http协议。也就是和之前系统的dns解析没有差别,但是得保证httpdns返回的ip是正确的。
- https下不会存在任何问题,证书校验依然使用域名进行校验
- cookie的问题也自然不存在。
同样的,解决了一部分问题后,也有一部分的风险。风险在哪呢?
- 过于底层,容灾不好做,除非强制关闭Httpdns。
- 服务器返回的ip如果不正确,这次请求就挂了,甚至下次也可能挂了。
- OkHttp默认对解析结果有一定时间的缓存,万一ttl过期了,okhttp可能依然会去使用,这时候也是有风险的。
对比两种方案,各有各的优点,一个方便做容灾,但同时也暴露出了很多问题,一个不方便做容灾,但是之前暴露出来的问题都不存在。所以,这时候就得根据实际情况衡量选择哪一种方案了。
还有就是WebView的HttpDns,目前看来Android的Webview简直就是一个Bug的存在,没有什么好的解决方法。在IOS中,Webview的请求是一个正常的HttpRequest对象,不会像Android中存在这种问题,Andorid中比较好的解决方法就是在native层的网络库里开一个代理服务器,将Webview的所有请求转发至这个代理服务器,由这个代理服务器将请求通过httpdns转换成ip请求,将请求结果返回给webview。
或者通过WebView的资源拦截接口拦截资源请求,不过这种方式只能处理资源,处理正常的http/https请求会存在问题,在Android5.0以下存在cookie种不进去的问题。
总之WebView就是蛋疼的存在,没有什么好的办法,除非有自己的Webview的容器~
Android OkHttp实现HttpDns的最佳实践(非拦截器)相关推荐
- Android OKHttp 可能你从来没用过的拦截器 【实用推荐】
前言 在平时开发中,你有没有下面这样的困扰呢? 场景一 明明是服务端的接口数据错误,而QA(测试)第一个找到的可能是客户端开发的你,为什么这个页面出现错误了? 而作为客户端开发的你,可能要拿出测试机连 ...
- 【Android】OkHttp源码解读逐字稿(1)-拦截器
目录 0.前言 1.OkHttp的简单使用 2.浅析开始 拦截器 链式调用流程示意图 第 0 个拦截器 第一个 拦截器 RetryAndFollowUpInterceptor 第二个拦截器 Bridg ...
- Android 6.0 权限管理最佳实践
博客: Android 6.0 运行时权限管理最佳实践 github: https://github.com/yanzhenjie/AndPermission
- Android车辆运动轨迹大数据采集最佳实践
csdn源码下载地址:https://download.csdn.net/download/geduo_83/10841480 前言: 最近帝都的天气有些冷,天寒地冻,天气虽冷,但也无法阻挡我写文章的 ...
- Android 加载GIF图最佳实践
转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/75578109 本文出自[赵彦军的博客] 起因 最近在项目中遇到需要在界面上显示一个 ...
- android 权限管理框架,Android 运行时权限管理最佳实践
欢迎访问我的个人博客 传送门 从 Android 6.0(API 级别 23)开始,用户开始在应用运行时向其授予权限,而不是在应用安装时授予.此方法可以简化应用安装过程,因为用户在安装或更新应用时不需 ...
- Okhttp 接入HttpDNS(支持http/https,)达到IP直连
HttpDns 是什么? HTTPDNS 利用 HTTP 协议与 DNS 服务器交互,代替了传统的基于 UDP 协议的 DNS 交互,绕开了运营商的 Local DNS,有效防止了域名劫持,提高域名解 ...
- Android开发最佳实践---Futurice之见
原文链接:https://github.com/futurice/android-best-practices 本文是Futurice公司的Android开发人员总结的最佳实践,遵循这些准则可以避免重 ...
- android double精度_Android车辆运动轨迹平滑移动(高仿滴滴打车)最佳实践
点击上方"Android技术杂货铺",选择"标星" 干货文章,第一时间送达! 作者:门心叼龙 链接:https://www.jianshu.com/p/015b ...
最新文章
- 服务器网页500错误修复工具,HTTP500错误是什么?如何修复
- Struts2利用iText导出word文档(包含表格)
- __init__()
- CentOS安装网络代理软件
- professional asp.net 4 with c# and VB.net 阅读笔记
- 【spring-session】错误:No bean named 'springSessionRepositoryFilter' available
- C# mysql 插入数据,中文乱码
- sql多语句表值函数_构造一个特殊的多语句表函数来检查SQL Server的运行状况
- [转载] Python OpenCV 基础教程
- 2 网段 Vlan+NAT 配置
- Android 屏幕画笔实现
- AutoCAD 安装
- 日剧推介:怨み屋本舗
- 计算机网络保密承诺书,保密承诺书集合5篇
- CompletableFuture模拟复杂场景使用测试。。。
- 两个div实现十字架
- Django实现用户管理
- Word2Vec教程 - Skip-Gram模型
- 【Origin】羡旁人
- 刚刚从Java培训班出来以及初学者怎么样才能通过面试?