本文档介绍了阿里云公共DNS Android SDK的接入和开发方式。
1.概述
阿里云公共DNS SDK是阿里云面向广大移动开发者提供DNS域名解析服务的开发工具包。
开发者利用本SDK,可以在自己的Android APP中轻松接入阿里云公共DNS,解决域名解析异常的问题,低成本实现域名解析精准调度。您可以参考Demo示例工程源码了解如何使用本SDK。
本SDK是基于对阿里公共DNS的DoH JSON API的封装,提供Java函数接口给Android APP进行域名解析,并且提供了基于TTL和LRU策略的高效域名缓存功能。在公共DNS原有功能的基础上,SDK还可以为用户带来以下优势:
简单易用
用户仅需集成我们提供的SDK,便可接入阿里云公共DNS业务。接入方法简单易用,为用户提供更为轻松便捷的解析服务。
零延迟
SDK内部实现了LRU的缓存机制,将每次域名解析后的IP缓存到本地;并且主动更新TTL过期缓存,保证缓存及时有效,从而帮助用户达到域名解析零延迟的效果。
2.SDK集成
您需先在控制台注册自己的应用,获取应用的唯一标识 Account ID
然后在自己工程目录下的AndroidManifest.xml文件中填写 AccessKey ID 和 AccessKey Secret 鉴权参数
集成SDK在自己的App工程项目中
2.1 通过gradle集成Maven方式集成SDK
在 build.gradle 文件中加入以下代码:
allprojects {
repositories {
maven {
url 'https://maven.aliyun.com/repository/public/'
}
mavenLocal()
mavenCentral()
}
}
加入你要引用的文件信息:
dependencies {
implementation 'com.alibaba.pdns:alidns-android-sdk:2.2.6'
implementation 'com.google.code.gson:gson:2.8.5'
}
2.2 通过aar方式集成SDK
通过控制台的链接阿里公共DNS SDK获取到的SDK的alidns_android_sdk.aar,将aar包集成到自己工程项目libs目录中即可轻松使用。
您可以通过以上这2种方式任选其一将SDK集成到自己的工程项目里。
2.3 SDK初始化
为了用户更好的使用SDK,避免出现解析不到IP地址的情况出现,请将SDK初始化的时间尽量提前。
您需先在控制台注册自己的应用,获取应用的唯一标识 AccountID 和鉴权参数 AccessKey ID 、AccessKey Secret , 集成SDK后并进行初始化,具体SDK初始化可参考在Application中的代码示例
public class DnsCacheApplication extends Application{
private String AccountID = "你的AccountID"; //设置您在控制台接入SDK的AccountID
private String AccessKey ID = "你的AccessKey ID"; //设置您在控制台接入SDK的AccessKey ID
private String AccessKey Secret = "你的AccessKey Secret "; //设置您在控制台接入SDK的AccessKey Secret
@Override
public void onCreate() {
super.onCreate();
DNSResolver.Init(this,AccountID,AccessKey ID, AccessKey Secret); //设置控制台接入SDK的AccountID AccessKey ID AccessKey Secret
//注意:设置缓存保持配置的域名会在TTL * 75%时自动发起解析,实现配置域名解析时始终能命中缓存,但是如果用户使用了CDN会导致TTL值很小,从而产生大量的解析请求造成费用上升,请用户谨慎使用该方法。
DNSResolver.setKeepAliveDomains(new String[]{"您要缓存保持的域名1","您要缓存保持的域名2",...});
DNSResolver.getInstance().preLoadDomains(DNSResolver.QTYPE_IPV4,new String[]{"您要预加载的域名1","您要预加载的域名2",...}); //设置指定IPV4类型域名预解析,将预加载域名替换为您希望使用阿里DNS解析的域名
}
}
DNSResolver为阿里公共DNS SDK的核心类,其内部封装了阿里公共DNS提供的DoH JSON API,将用户的目标域名解析成对应的IP。接入阿里公共DNS SDK时建议在Application子类里集成。
另外,Android工程在使用SDK时,需要保证提供以下访问权限的配置:
<!--需要配置的权限-->
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
2.4 SDK鉴权
本SDK从2.0开始支持设置鉴权认证功能,来保障用户身份安全,不被第三方未授权者盗用。鉴权功能开启,请参考创建密钥在控制台上创建 AccessKey ID 和 AccessKey Secret 。如果用户在接入SDK初始化时不设置鉴权参数,则后期公共DNS会拒绝没有开启鉴权功能的域名解析请求, 会造成域名解析功能失效影响到用户实际的业务,因此您在接入阿里云公共DNS SDK初始化时务必要设置鉴权参数。
鉴权参数可以通过以下2种方式进行设置鉴权:
SDK初始化Init方法里直接设置
DNSResolver.Init(this,AccountID,AccessKey ID, AccessKey Secret);
可以通过在应用的AndroidManifest.xml文件中添加以下配置:
<meta-data
android:name="com.alibaba.pdns.ACCESS_KEY_ID"
android:value="替换成您在阿里云控制台注册app时生成的AccessKey ID" />
<meta-data
android:name="com.alibaba.pdns.ACCESS_KEY_SECRET"
android:value="替换成您在阿里云控制台注册app时生成的AccessKey Secret" />
鉴权参数的配置以上2种方法开发者可以根据自身业务需要选择其中一种即可
3. SDK接入常见问题
Android 9.0 发送HTTP网络请求会报cleartext HTTP traffic no permitted异常
原因:从Android9.0(API 28)开始,Android默认禁止明文访问网络只允许使用https url访问。
解决方案
在应用的AndroidManifest.xml文件的<application>中添加代码:
android:usesCleartextTraffic="true"
<application
android:name=".DnsCacheApplication"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true">
Android9.0会报异常:Didn't find class BasicHttpParams。
原因:Apache Http客户端弃用 。
因为早在Android 6.0中,谷歌取消了对Apache Http客户端的支持。从Android 9.0开始,org.apache.http.legacy从bootclasspath中删除。
该修改对于大多数 taskVersion < 9.0的应用没有影响,对所有taskVersion > 9.0的应用,如果继续使用Apache Http接口或者引用的lib包中用到该接口时,都会出现Apache Http接口找不到的异常。
解决方案
在应用的AndroidManifest.xml文件的<application>中添加:
<uses-library android:name="org.apache.http.legacy" android:required="false"/>
本SDK从2.1.9版本开始引入了JNI,需要在您的App工程项目的开发环境中配置NDK
在App工程项目的根目录里local.properties文件中添加NDK的安装目录
ndk.dir=...\\ndk\\21.4.7075529 ...是开发者本地安装NDK的路径
在App工程项目的根目录里gradle.properties文件中添加以下配置
android.useDeprecatedNdk = true
如果您的App工程项目已经有配置NDK,可以忽略无需再配置了。为了更好的使用本SDK,建议您在编译APP时将JDK的版本设置为1.8,NDK的版本设置为21.4.7075529。
4. API介绍
4.1 常用设置
4.1.1 Init方法初始化
在您Application中初始化SDK时调用Init方法。
DNSResolver.Init(this, AccountID, AccessKey ID, AccessKey Secret);
本SDK为开发者提供了2种鉴权配置方式,读者请任选其一即可,具体请查照本文档中2.4 SDK鉴权章节描述。
4.1.2 设置预解析域名
在您初始化程序时,可以选择性地预先向阿里公共DNS SDK中注册您后续可能会使用到的域名,以便SDK提前解析,减少后续解析域名时请求的时延。调用以下方法设置预解析域名:
指定预加载IPV6或IPV4域名解析
//设置指定域名类型预先解析,将预加载域名替换为您希望使用阿里DNS解析的域名
DNSResolver.getInstance().preLoadDomains(DNSResolver.QTYPE_IPV4,new String[]{...})
DNSResolver.QTYPE_IPV4 预取域名解析的IPV4记录类型
DNSResolver.QTYPE_IPV6 预取域名解析的IPV6记录类型
根据当前网络自动匹配预加载IPV6或IPV4域名解析,在双栈网络环境下预加载IPV6和IPV4类型的域名解析
DNSResolver.getInstance().preLoadDomains(domains)
预解析接口设置的同时会实时触发异步网络请求,应该在代码逻辑上确保调用预解析接口时,已经进行了必要的初始化设置。
4.1.3 设置域名缓存保持
SDK支持设置缓存保持配置的域名会在TTL * 75%时自动发起解析,实现配置的域名在解析时始终能命中缓存提升了SDK的解析效率。此项建议不要设置太多域名,当前限制为最多 10 个域名与预解析分开独立配置。
DNSResolver.setKeepAliveDomains(new String[]{"用户指定域名1", "用户指定域名2"});
优势
1. 可及时(ttl过期前)更新记录
2. 配合预加载可降低首次解析延迟(0毫秒)
劣势
1. 根据ttl *75% 作为重新请求的时机,会带来额外的费用
4.1.4 设置是否使用服务端IPV6地址
阿里公共DNS服务支持IPV4、IPV6双栈地址访问,通过DNSResolver.setEnableIPv6(boolean enable)方法来设置是否使用服务端IPV6地址。当设置为true表示使用IPV6的IP地址访问服务端接口,false表示使用IPV4的IP地址访问服务端接口。如不显式设置,默认为使用IPV4地址访问。另外当设置为IPV6地址时,当访问阿里公共DNS服务不通时则自动切换为IPV4地址,并且支持重试3次策略。
4.1.5 设置缓存的最大个数
DNSResolver.getInstance().setMaxCacheSize(CACHE_MAX_NUMBER); //设置缓存的最大个数,默认为100
用户可以自定义最大count的值。
4.1.6 设置访问服务端协议
SDK支持设置DNS解析HTTP请求协议类型,可自主选择通过HTTP或HTTPS协议解析。SDK默认并推荐使用HTTPS协议进行解析,因为HTTPS协议安全性更好。公共DNS的计费项是按HTTP的解析次数进行收费,其中HTTPS是按5倍HTTP流量进行计费,开发者可以根据自身实际业务需要选择HTTP请求协议类型。
DNSResolver.setSchemaType(DNSResolver.HTTPS); 默认访问为https的模式。
DNSResolver.HTTP,以HTTP协议访问服务端接口
DNSResolver.HTTPS,以HTTPS协议访问服务端接口
4.1.7 设置IP测速socket监测的端口号
DNSResolver.setSpeedPort(DNSResolver.PORT_80)
用户可以设置IP测速基于socket监测的端口号,默认为80
4.2 其它高级设置
4.2.1 设置是否开启SDK调试日志开关
DNSResolver.setEnableLogger(true); //默认关闭SDK调试日志
用户可以设置是否开启SDK调试日志开关(true为开启调试日志,false为关闭调试日志)
4.2.2 设置是否开启使用公共DNS解析失败时自动降级到localdns进行兜底解析
DNSResolver.setEnableLocalDns(true); //默认开启使用阿里云公共DNS解析失败时自动降级到localdns兜底解析
4.2.3 设置是否开启Short模式
阿里公共DNS的DoH JSON API返回数据类型分为全量JSON和简要IP数组格式,可以通过调用DNSResolver.setEnableShort (boolean enable)来开启或关闭short模式。如不显式设置,默认为关闭short模式。如下方式:
DNSResolver.setEnableShort (true); //默认值是false,该参数用户可以不需设置,不设置则默认为false。
short模式为SDK调用阿里公共DNS服务返回的比较简单的IP数组,可以减少响应的数据量,适用于对网络流量敏感的场景。
4.2.4 设置是否开启缓存永不过期
DNSResolver.setImmutableCacheEnable(false); //默认不开启缓存永不过期
SDK内部共有三种缓存更新机制:
缓存永不过期:一旦启用此功能,那么在app启动运行过程中,将始终视缓存为有效状态,不再执行缓存过期检查和更新操作,用户不需要设置
setKeepAliveDomains
来主动更新缓存,可以最大程度降低用户解析次数。设置方法:
DNSResolver.setImmutableCacheEnable(boolean var0)
参数说明:当参数
var0
为true
时,启用缓存永不过期功能;当var0
为false
时,关闭缓存永不过期功能。主动更新缓存:主动更新是为了确保解析命中最新解析记录值缓存,当域名的权威解析出现变更时,使用本机制既可以保证解析请求命中缓存,从而DNS降低时延,又可以确保获取的解析记录缓存通常都是最新的记录值。当设置的域名的TTL值达到75%时,SDK自动触发解析查询并更新缓存。建议控制主动更新的域名数量,最大支持10个。
设置方法:
DNSResolver.setKeepAliveDomains(String[] var1)
参数说明:
var1
是需要主动更新的域名字符串数组。被动更新缓存:
调用下面两个获取解析结果方法时,会被动更新缓存:
getIPsV4ByHost(String hostName)
方法:获取hostName对应的IPv4记录数组。如果缓存非空且在TTL有效期内,会直接返回缓存结果,否则,将先通过网络请求获取最新解析结果,然后再返回该结果并更新缓存,该方法多用于对解析结果有较高准确性要求的场景。getIpv4ByHostFromCache(String hostName, boolean isAllowExp)
方法:从缓存中获取hostName对应的IPv4记录数组。此方法会根据isAllowExp
参数值的不同,决定是否返回缓存中已过期的解析结果。该方法建议在app启动时配合preload预加载方法使用,保证app启动时就会缓存最新的解析结果。参数说明:若
isAllowExp
为true
,即使缓存过期也返回旧记录(缓存为空时返回null
),并通过异步请求更新缓存;若为false
,当缓存已过期或者为空时,返回null
,并通过异步请求更新缓存。
推荐示例:
String[] IPArray = mDNSResolver.getIpv4ByHostFromCache(hostname,true); if (IPArray == null || IPArray.length == 0){ IPArray = mDNSResolver.getIPsV4ByHost(hostname); }
4.2.5 设置是否开启使用缓存
DNSResolver.setEnableCache(true); //默认开启使用缓存
用户可以设置是否开启使用缓存功能(true为开启缓存功能,false为关闭缓存功能)
4.2.6 设置是否开启IP测速
DNSResolver.setEnableSpeedTest(false); //默认不开启IP测速
用户可以设置是否开启IP测速(true为开启IP测速功能,false为关闭IP测速功能)
4.2.7 设置是否开启依据ISP网络区分域名缓存
DNSResolver.setIspEnable(true);//是否开启依据ISP网络区分域名缓存
设置是否开启依据ISP网络区分域名缓存。如果开启,则在不同网络环境下域名缓存数据分别存储互不影响。如果不开启,则不同网络下使用同一份域名缓存数据
4.2.8 设置否定缓存的最大TTL时间
DNSResolver.setMaxNegativeCache(MAX_NEGATIVE_CACHE);//设置否定缓存的最大TTL时间,默认为30秒
用户可以根据自身的需求设置否定缓存(域名没有配置对应的IP地址,导致解析结果没有IP返回的无效缓存)的最大TTL时间。
4.2.9 设置缓存的最大TTL时间
DNSResolver.setMaxTtlCache(MAX_TTL_CACHE);//设置缓存的最大TTL时间,默认为3600秒
SDK可设置缓存的最大TTL时间,如果设置了该时间,则会限制缓存的最大TTL不超过该设置时间。SDK默认该参数为3600s。
4.2.10 设置客户端子网信息
DNSResolver.setEdnsSubnet("1.2.XX.XX/24");
setEdnsSubnet是为了支持DNS ECS功能(RFC7871),将用户的子网信息传递给权威DNS,以便进行更精确的DNS解析和流量调度。其中,掩码越长的地址信息越精确,掩码越短则用户隐私效果越好,建议使用“/24”掩码长度。
该参数是特地为DNS代理(proxy)使用DoH JSON API场景设计,即用户发送DNS查询给DNS代理,DNS代理通过该参数携带用户的子网信息传递给阿里公共DNS,最后传递到权威DNS服务器。
例如DNSResolver.setEdnsSubnet("1.2.XX.XX/24"),权威服务器会收到基于1.2.XX.XX/24地址前缀信息来帮助用户选择DNS链路。
5.反混淆配置
-keep class com.alibaba.pdns.** {*;}
6.服务API
/**
* 通过自动感知当前网络环境(IPV4-only、IPV6-only、IPV4和IPV6双栈)预加载域名解析
* 双栈网络环境下同时预加载IPV4和IPV6类型的域名解析结果。可在应用启动时对SDK初始化时调用,
* 对域名的解析结果提前存入缓存中,加快后续的域名解析时延。
*
* @param domains 预加载解析的域名
*/
public void preLoadDomains(final String[] domains)
/**
* 指定预加载IPV6或IPV4域名进行预加载解析
* 可在应用启动时对SDK初始化时调用,对域名的解析结果提前存入缓存中,加快后续的域名解析时延
*
* @param qType 预加载解析IPV4还是IPV6
* @param domains 预加载解析的域名
*/
public void preLoadDomains(String qType, final String[] domains)
/**
* 通过自动感知当前网络环境(IPV4-only、IPV6-only、IPV4和IPV6双栈)获取该域名的解析数据
* 如果缓存中存在解析结果且缓存没过期则将缓存里的解析结果返回给用户
* 如果缓存没有或缓存过期则先通过同步网络请求向服务端获取域名的递归解析结果返回给用户,然后在将解析结果存入缓存中
*
* @param host 用户所要解析的域名
* @return 返回根据当前网络环境下的最优IP数组
*/
public String[] getIpsByHost(String host)
/**
* 获取hostName对应IPV4记录数组
* 如果缓存中存在解析结果且缓存没过期则将缓存里的解析结果返回给用户
* 如果缓存没有或缓存过期则先通过同步网络请求向服务端获取域名的递归解析结果返回给用户,然后在将解析结果存入缓存中
*
* @param hostName例如(www.taobao.com)
* @return 返回目标hostName对应的IPV4地址的数组
*/
public String[] getIPsV4ByHost(String hostName)
/**
* 获取hostName对应IPV6记录数组
* @param hostName例如(www.taobao.com)
* @return 返回目标hostName对应的IPV6地址的数组
*/
public String[] getIPsV6ByHost(String hostName)
/**
* 通过自动感知当前网络环境(IPV4-only、IPV6-only、IPV4和IPV6双栈)从缓存中获取该域名解析后的IP数组
* 如果缓存没有,该方法是先直接返回null,然后同时进行异步查询,最后将查询到的数据存入缓存中
* 如果缓存存在解析结果,如果允许返回缓存过期解析结果,则先将过期的解析IP返回给用户,再进行异步更新缓存解析结果
* 如果不允许返回缓存过期解析结果,当缓存过期时先直接返回null给用户,然后再进行异步更新缓存解析结果
*
* @param host 查询的host 例如(www.taobao.com)
* @param isAllowExp 是否允许返回已过期域名的解析数据
* @return 获取缓存中对应host解析后的IP数组
*/
public String[] getIpsByHostFromCache(String host, boolean isAllowExp)
/**
* 从缓存中获取该域名解析后的IPV4记录类型的IP数组
* 如果缓存没有,该方法是先直接返回null,然后同时进行异步查询,最后将查询到的数据存入缓存中
* 如果缓存存在解析结果,如果允许返回缓存过期解析结果,则先将过期的解析IP返回给用户,再进行异步更新缓存解析结果
* 如果不允许返回缓存过期解析结果,当缓存过期时先直接返回null给用户,然后再进行异步更新缓存解析结果
*
* @param host 查询的host 例如(www.taobao.com)
* @param isAllowExp 是否允许返回已过期域名的解析数据
* @return 获取缓存中对应host解析后的IPV4记录类型的IP数组
*/
private String[] getIpv4ByHostFromCache(String host , boolean isAllowExp)
/**
* 从缓存中获取该域名解析后的IPV6记录类型的IP数组
* 如果缓存没有,该方法是先直接返回null,然后同时进行异步查询,最后将查询到的数据存入缓存中
* 如果缓存存在解析结果,如果允许返回缓存过期解析结果,则先将过期的解析IP返回给用户,再进行异步更新缓存解析结果
* 如果不允许返回缓存过期解析结果,当缓存过期时先直接返回null给用户,然后再进行异步更新缓存解析结果
*
* @param host 查询的host 例如(www.taobao.com)
* @param isAllowExp 是否允许返回已过期域名的解析数据
* @return 获取缓存中对应host解析后的IPV6记录类型的IP数组
*/
private String[] getIpv6ByHostFromCache(String host , boolean isAllowExp)
/**
* 获取url对应IPv4记录的DomainInfo对象数组
* 如果缓存中存在解析结果且缓存没过期则将缓存里的解析结果返回给用户
* 如果缓存没有或缓存过期则先通过同步网络请求向服务端获取域名的递归解析结果返回给用户,然后在将解析结果存入缓存中
*
* @param url例如(http://www.taobao.com)
* @return目标url对应IPV4类型的DomainInfo对象数组
*/
public DomainInfo[] getIPsV4DInfoByUrl(String url)
注意:DomainInfo对象中的url为替换host为IP拼接后的url,用户不需再手动url的替换拼接。
/**
* 获取url对应IPv6记录的DomainInfo对象数组
* 如果缓存中存在解析结果且缓存没过期则将缓存里的解析结果返回给用户
* 如果缓存没有或缓存过期则先通过同步网络请求向服务端获取域名的递归解析结果返回给用户,然后在将解析结果存入缓存中
*
* @param url 例如(http://m.taobao.com)
* @return 目标url对应IPV6类型的DomainInfo对象数组
*/
public DomainInfo[] getIPsV6DInfoByUrl(String url)
/**
* 获取url对应IPV4记录的DomainInfo对象
* 如果缓存中存在解析结果且缓存没过期则将缓存里的解析结果返回给用户
* 如果缓存没有或缓存过期则先通过同步网络请求向服务端获取域名的递归解析结果返回给用户,然后在将解析结果存入缓存中
*
* @param url 例如(http://m.taobao.com)
* @return 目标url对应IPV4类型的DomainInfo对象集合中随机的一个
*/
public DomainInfo getIPV4DInfoByUrl(String url)
/**
* 获取url对应IPV6记录的DomainInfo对象
* 如果缓存中存在解析结果且缓存没过期则将缓存里的解析结果返回给用户
* 如果缓存没有或缓存过期则先通过同步网络请求向服务端获取域名的递归解析结果返回给用户,然后在将解析结果存入缓存中
*
* @param url 例如(http://www.taobao.com)
* @return 目标url对应IPV6类型的DomainInfo对象集合中随机的一个
*/
public DomainInfo getIPV6DInfoByUrl(String url)
说明:返回的domainInfo对象,主要是封装了如下属性
/**
* id访问域名自增的id编号
*/
public String id = null;
/**
* 可以直接使用的url 已经替换了host为ip后的url
*/
public String url = null;
/**
* 需要设置到http header里面的目标服务名称
*/
public String host = "";
/**
* 返回的内容体
*/
public String data = null;
/**
* 开始请求的时间
*/
public String startTime = null;
/**
* 请求结束的时间,如果请求超时,该值为null
*/
public String stopTime = null;
/**
* server返回的状态值200 \ 404 \ 500等
*/
public String code = null;
/**
* 获取hostName对应IPV4记录
* 如果缓存中存在解析结果且缓存没过期则将缓存里的解析结果返回给用户
* 如果缓存没有或缓存过期则先通过同步网络请求向服务端获取域名的递归解析结果返回给用户,然后在将解析结果存入缓存中
* @param hostName例如(www.taobao.com)
* @return 返回目标hostName对应的IPV4地址集合中的一个随机IPV4地址,当开启测速返回一个最优IPV4地址
*/
public String getIPV4ByHost(String hostName)
/**
* 获取hostName对应IPV6记录
* 如果缓存中存在解析结果且缓存没过期则将缓存里的解析结果返回给用户
* 如果缓存没有或缓存过期则先通过同步网络请求向服务端获取域名的递归解析结果返回给用户,然后在将解析结果存入缓存中
* @param hostName例如(www.taobao.com)
* @return 返回目标hostName对应的IPV6地址集合中的一个随机IPV6地址,当开启测速返回一个最优IPV6地址
*/
public String getIPV6ByHost(String hostName)
/**
* 获取请求阿里公共DNS成功失败统计信息
*
* @return 所有的域名解析统计信息Json数组字符串
*/
public String getRequestReportInfo()
/**
* 设置域名缓存保持,配置的域名会在TTL * 75%时自动发起解析, 实现配置的域名在解析时始终能命中缓存提供了SDK的解析效率。
* 此项建议不要设置太多域名,当前限制为最多 10 个域名,与预解析分开独立配置
*
* @param persistentCacheDomains
*/
public synchronized static void setKeepAliveDomains(String[] persistentCacheDomains) {
/**
* 清除指定域名缓存,hostname为null时清除所有域名缓存
*
* @param domains 指定删除缓存里的域名数组
*/
public void clearHostCache(String[] domains){
7.API使用示例
URl:传进来的访问地址,例如:http://www.taobao.com。
String hostname = "www.taobao.com";
String url = "http://www.taobao.com";
7.1 获取当前网络环境下的最优IP数据
String[] ip = DNSResolver.getInstance().getIpsByHost(hostname); //获取当前网络下的最优域名解析IP
7.2 根据当前网络环境预加载域名解析
DNSResolver.getInstance().preLoadDomains(domains) //设置域名预先解析,将预加载域名替换为您希望使用阿里DNS解析的域名
7.3 根据当前网络环境读取缓存中的域名解析数据
String[] ip = DNSResolver.getInstance().getIpsByHostFromCache(hostname,true);//获取当前网络环境缓存中的域名解析数据
7.4 获得IPv4地址
String IPV4 = DNSResolver.getInstance().getIPV4ByHost(hostname); //获取IPV4的域名解析
7.5 获得IPv6地址
String IPV6 = DNSResolver.getInstance().getIPV6ByHost(hostname) //获取IPV6的域名解析
7.6 从缓存中获取ipv4解析地址
String[] IPV4 = DNSResolver.getInstance().getIpv4ByHostFromCache(hostname , true) //获取缓存里IPV4的域名解析
7.7 从缓存中获取ipv6解析地址
String[] IPV6 = DNSResolver.getInstance().getIpv6ByHostFromCache(hostname , true) //获取缓存里IPV6的域名解析
7.8 获得URL对应的DomainInfo对象
DomainInfo dinfo = DNSResolver.getInstance().getIPV4DInfoByUrl(url); //获取替换的URL
7.9 清除缓存中指定域名解析结果
DNSResolver.getInstance().clearHostCache(hostName); //清除指定域名缓存,hostName设为null则清除所有域名缓存
7.10 获取请求阿里DNS成功失败统计信息
String reportInfo = DNSResolver.getInstance().getRequestReportInfo();//获取成功失败统计信息
所有的域名解析的统计信息JSON字符串数组中的字段含义描述如下:
[
{
"avgRtt":"1", // 域名平均解析时间,单位:毫秒(ms)
"degradeLocalDnsCount": 0, // 降级到LocalDNS的次数
"domainName":"www.example.com", // 解析的域名
"hitDnsCacheCount": 1, // 命中缓存的次数
"httpabnormalCount": 0, // 递归请求失败的次数
"isp": "中国移动", // 运营商名称
"localDnsResolveErrCount": 0, // LocalDNS解析失败次数
"maxRtt": 8.0, // 域名最大解析时间,单位:毫秒(ms)
"nonetworkCount": 0, // 无网络次数
"permissionErrCount": 0, // 用户鉴权失败次数
"queryType": 1, // ip类型,1代表ipv4、28代表ipv6
"recursiveReqCount": 1, // 递归查询的次数
"reqParameterErrCount": 0, // 请求参数格式错误次数
"reqPathErrCount": 0, // URL错误次数
"reqServerErrCount": 0, // DNS服务端错误次数
"reqTimeoutCount": 0, // DNS服务超时错误次数
"resolveSuccessCount": 1, // 解析成功次数
"timeoutCount": 0, // 网络超时错误次数
"utfNetWorkErroNum": 0 // 数据上报超时错误次数
}
......
]
请求阿里公共DNS域名解析统计数据是以网络环境+域名+请求类型为统计维度。
8. 示例
public class MainActivity extends AppCompatActivity {
private Button button;
private TextView tvInfo;
private TextView tvResult;
private String hostUrl = "http://www.taobao.com"; //请替换为您需要解析hostUrl
private String hostName = "www.taobao.com"; //请替换为您需要解析hostName
private static final String TAG = "PDnsDemo";
private static ExecutorService pool = Executors.newSingleThreadExecutor();
private static final String PDNS_RESULT = "pdns_result";
private static final int SHOW_CONSOLE_TEXT = 10000;
private Handler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.demo_activity_main);
init();
initHandler();
}
private void init() {
tvInfo = findViewById(R.id.tv_respons_info);
tvResult = findViewById(R.id.tv_respons);
button = findViewById(R.id.btn_onclik);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
new Thread(new Runnable() {
@Override
public void run() {
//调用阿里公共sdk里的getIPV4ByHost方法获得目标域名解析后的IP
String ip = DNSResolver.getInstance().getIPV4ByHost(hostName);
if(ip != null){
tvInfo.setText("您解析域名的IP是:"+ ip);
}
//调用阿里公共sdk里getIPV4DInfoByUr获取目标域名解析后的domainInfo对象中的URL,该URL为已替换原来url中host为IP的url
DomainInfo dinfo = DNSResolver.getInstance().getIPV4DInfoByUrl(hostUrl);
if (dinfo != null) {
showResponse(dinfo);
}
}
}).start();
}
});
}
private void initHandler() {
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case SHOW_CONSOLE_TEXT:
tvResult.setText(msg.getData().getString(PDNS_RESULT) + "\n");
break;
}
}
};
}
private void showResponse(final DomainInfo dinfo) {
//发送网络请求
String requestUrl = dinfo.url;
HttpURLConnection conn = null;
try {
URL url = new URL(requestUrl);
conn = (HttpURLConnection) url.openConnection();
//使用IP的方式进行访问时,需要设置HTTP请求头的HOST字段为原来的域名
conn.setRequestProperty("Host", url.getHost());//设置HTTP请求头HOST字段
DataInputStream dis = new DataInputStream(conn.getInputStream());
int len;
byte[] buff = new byte[4096];
StringBuilder response = new StringBuilder();
while ((len = dis.read(buff)) != -1) {
response.append(new String(buff, 0, len));
}
Log.d(TAG, "Response: " + response.toString());
dis.close();
sendMessage(response.toString());
} catch (IOException e) {
e.printStackTrace();
}finally {
if (conn != null) {
conn.disconnect();
}
}
}
private void sendMessage(String message) {
if (mHandler != null) {
Message msg = mHandler.obtainMessage();
Bundle bundle = new Bundle();
bundle.putString(PDNS_RESULT, message);
msg.setData(bundle);
msg.what = SHOW_CONSOLE_TEXT;
mHandler.sendMessage(msg);
}
}
}
public class DnsCacheApplication extends Application {
private String AccountID = "你的AccountID"; //设置您在控制台接入SDK的AccountID
private String AccessKey ID = "你的AccessKey ID"; //设置您在控制台接入SDK的AccessKey ID
private String AccessKey Secret = "你的AccessKey Secret"; //设置您在控制台接入SDK的AccessKey Secret
@Override
public void onCreate() {
super.onCreate();
DNSResolver.Init(this,AccountID, AccessKey ID, AccessKey Secret); //设置控制台接入SDK的AccountID AccessKey ID AccessKey Secret
DNSResolver.setKeepAliveDomains(new String[]{"用户指定域名1","用户指定域名2",...}); //设置缓存保持配置的域名会在TTL * 75%时自动发起解析,实现配置域名解析时始终能命中缓存
DNSResolver.getInstance().preLoadDomains(DNSResolver.QTYPE_IPV4,new String[]{"您要预加载的域名1","您要预加载的域名2",...}); //设置指定IPV4类型域名预解析,将预加载域名替换为您希望使用阿里DNS解析的域名
}
}
注意事项
通过阿里公共DNS获得域名的IP地址后,客户端可以使用这个IP发送业务请求,HTTP请求头的Host字段需改为原来的域名。
为了保证用户业务正常,当通过阿里云公共DNS SDK获取到域名解析对应的IP为空时,需要应用开发者使用原域名的请求url地址进行降级请求,示例代码如下:
String ip = DNSResolver.getInstance().getIPV4ByHost("域名"); if (ip != null) { //替换url中的host为ip进行接口请求 }else { //使用原域名的请求url地址进行降级请求(使用原带域名的url进行网络请求) }
为帮助用户更快使用阿里公共DNS SDK,我们为开发者提供了Demo程序,读者可以下载到本地作为参考请点击这里,下载Demo程序。
用户在SDK接入完成后,为了验证接入是否成功,需要在控制台“流量分析”中查看是否有流量产生,如果没有流量产生请检查Account ID 、AccessKey ID 和 AccessKey Secret参数是否设置正确。