欢迎访问 生活随笔!

生活随笔

当前位置: 首页 >

HttpDNS功能说明及实现

发布时间:2024/2/28 69 豆豆
生活随笔 收集整理的这篇文章主要介绍了 HttpDNS功能说明及实现 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

功能说明

HTTPDNS使用HTTP协议进行域名解析,代替现有基于UDP的DNS协议,域名解析请求直接发送到阿里云的HTTPDNS服务器,从而绕过运营商的Local DNS,能够避免Local DNS造成的域名劫持问题和调度不精准问题。

功能说明
防劫持绕过运营商Local DNS,避免域名劫持,让每一次访问都畅通无阻。
精准调度基于访问的来源IP,获得最精准的解析结果,让客户端就近接入业务节点。
0ms解析延迟通过热点域名预解析、缓存DNS解析结果、解析结果懒更新策略等方式实现0解析延迟
快速生效避免Local DNS不遵循权威TTL,解析结果长时间无法更新的问题
降低解析失败率有效降低无线场景下解析失败的比率

防劫持

HTTPDNS代替了传统的LocalDNS完成递归解析的功能,基于HTTP协议的设计可以适用于几乎所有的网络环境,同时保留了鉴权、HTTPS等更高安全性的扩展能力,避免恶意攻击劫持行为。

精准调度

传统域名解析的调度精准性问题,本质根源在于Local DNS的部署和分配机制上。由于碎片化的管理方式,这些环节的服务质量同样很难得到保障。HTTPDNS在递归解析实现上优化了与权威DNS的交互,通过<a name="https://datatracker.ietf.org/doc/rfc7871">edns-client-subnet</a>协议将终端用户的IP信息直接交付给权威DNS,这样权威DNS就可以忽略Local DNS IP信息,根据终端用户的IP信息进行精准调度,避免Local DNS的坐标干扰

DNS解析0延迟:

  • 构建客户端DNS缓存;

    通过合理的DNS缓存,我们确保每次网络交互的DNS解析都是从内存中获取IP信息,从而大幅降低DNS解析开销。根据业务的不同,我们可以制订更丰富的缓存策略,如根据运营商缓存,可以在网络切换的场景下复用已缓存的不同运营商线路的域名IP信息,避免网络切换后进行链路重选择引入的DNS网络解析开销。另外,我们还可以引入IP本地化离线存储,在客户端重启时快速从本地读取域名IP信息,大幅提升首页载入效率。
  • 热点域名预解析;

    在客户端启动过程中,我们可以通过热点域名的预解析完成热点域名的缓存载入。当真正的业务请求发生时,直接由内存中读取目标域名的IP信息,避免传统DNS的网络开销。
  • 懒更新策略;

    绝大多数场景下业务域名的IP信息变更并不频繁,特别是在单次APP的使用周期内,域名解析获取的IP往往是相同的(特殊业务场景除外)。因此我们可以利用DNS懒更新策略来实现TTL过期后的DNS快速解析。所谓DNS懒更新策略即客户端不主动探测域名对应IP的TTL时间,当业务请求需要访问某个业务域名时,查询内存缓存并返回该业务域名对应的IP解析结果。如果IP解析结果的TTL已过期,则在后台进行异步DNS网络解析与缓存结果更新。通过上述策略,用户的所有DNS解析都在与内存交互,避免了网络交互引入的延迟。

实现方案

服务端:

服务端提供API接口,app端直接通过ip地址访问,ip地址可以有多个

请求方式:HTTP GET

URL参数说明:

名称是否必须描述
host必须要解析的域名
ip可选用户的来源IP,如果没指定这个参数,默认使用请求连接的源IP

请求示例:

  • 示例1(默认来源IP):http://x.x.x.x/d?host=www.suning.com

  • 示例2(指定来源IP):http://x.x.x.x/d?host=www.suning.com&ip=185.53.179.6

考虑到服务IP防攻击之类的安全风险,为保障服务可用性,HTTPDNS同时提供多个服务IP,当某个服务IP在异常情况下不可用时,可以使用其它服务IP进行重试。

请求成功时,HTTP响应的状态码为200,响应结果用JSON格式表示,示例如下:

{"host": "www.suning.com","ips": ["112.84.104.48"],"ttl": 57,"origin_ttl": 120 }

请求失败的响应示例:

{"code": "MissingArgument" }

错误码列表如下:

错误码HTTP状态码描述
MissingArgument400缺少必要参数
InvalidHost400域名格式不合法
MethodNotAllowed405不支持的HTTP方法
InternalError500服务端内部错误

错误处理

异常下的出错兼容逻辑,主要包括异步请求,重试,降级

异步请求

访问HTTPDNS服务时,应该使用异步请求的策略,避免解析延迟太大而对业务造成影响,特别是在网络环境异常或HTTPDNS服务IP异常不可 用时,如果用同步访问,需要等待网络超时后才会返回解析失败,这个超时时间较大,可能对业务的使用体验造成很大影响。异步请求策略:解析域名时,如果当前缓存中有TTL未过期的IP,可直接使用;如果没有,则立刻让此次请求降级走原生LocalDNS解析,同 时另起线程异步地发起HTTPDNS请求进行解析,更新缓存,这样后续解析域名时就能命中缓存。

重试

访问HTTPDNS服务解析域名时,如果请求HTTPDNS服务端失败,即HTTP请求没有返回,可以进行重试。大部分情况下,这种访问失败是由于网络原因引起的,重试可以解决。

降级

不管是因为什么原因,当通过HTTPDNS服务无法获得域名对应的IP时,都必须降级:使用标准的DNS解析,通过Local DNS去解析域名。

Android端:

OkHttp默认使用系统DNS服务InetAddress进行域名解析,但同时也暴露了自定义DNS服务的接口,通过该接口我们可以优雅地使用HttpDns。

  • 自定义DNS接口

OkHttp暴露了一个Dns接口,通过实现该接口,我们可以自定义Dns服务:

public class OkHttpDns implements Dns {private static final Dns SYSTEM = Dns.SYSTEM;HttpDnsService httpdns;//httpdns 解析服务private static OkHttpDns instance = null;private OkHttpDns(Context context) {this.httpdns = HttpDns.getService(context, "account id");}public static OkHttpDns getInstance(Context context) {if(instance == null) {instance = new OkHttpDns(context);}return instance;}@Overridepublic List<InetAddress> lookup(String hostname) throws UnknownHostException {//通过异步解析接口获取ipString ip = httpdns.getIpByHostAsync(hostname);if(ip != null) {//如果ip不为null,直接使用该ip进行网络请求List<InetAddress> inetAddresses = Arrays.asList(InetAddress.getAllByName(ip));Log.e("OkHttpDns", "inetAddresses:" + inetAddresses);return inetAddresses;}//如果返回null,走系统DNS服务解析域名return Dns.SYSTEM.lookup(hostname);} }
  • 创建OkHttpClient

创建OkHttpClient对象,传入OkHttpDns对象代替默认Dns服务:

private void okhttpDnsRequest() {OkHttpClient client = new OkHttpClient.Builder().dns(OkHttpDns.getInstance(getApplicationContext())).build();Request request = new Request.Builder().url("http://www.aliyun.com").build();Response response = null;client.newCall(request).enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {e.printStackTrace();}@Overridepublic void onResponse(Call call, Response response) throws IOException {if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);DataInputStream dis = new DataInputStream(response.body().byteStream());int len;byte[] buff = new byte[4096];StringBuilder result = new StringBuilder();while ((len = dis.read(buff)) != -1) {result.append(new String(buff, 0, len));}Log.d("OkHttpDns", "Response: " + result.toString());}}); }
  • 总结

相比于通用方案,OkHttp+HttpDns有以下两个主要优势:

实现简单,只需通过实现Dns接口即可接入HttpDns服务通用性强,该方案在HTTPS,SNI以及设置Cookie等场景均适用。规避了证书校验,域名检查等环节

IOS端:

基于NSURLProtocol可拦截iOS系统上基于上层网络库NSURLConnection/NSURLSession发出的网络请求;

通过以下接口注册自定义NSURLProtocol,用于拦截上层网络请求,并创建新的网络请求接管数据发送、接收、重定向等处理逻辑,将结果反馈给原始请求。

[NSURLProtocol registerClass:[CustomProtocol class]];

自定义NSURLProtocol处理过程概述:

  • 在canInitWithRequest中过滤要需要做HTTPDNS域名解析的请求;
  • 请求拦截后,做HTTPDNS域名解析;
  • 解析完成后,同普通请求一样,替换URL.host字段,替换HTTP Header Host域,并接管该请求的数据发送、接收、重定向等处理;



作者:刚哥说
链接:https://www.jianshu.com/p/15ff2aeb5b5b
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

总结

以上是生活随笔为你收集整理的HttpDNS功能说明及实现的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。