本文档介绍了移动解析HTTPDNS Harmony SDK的接入和开发方式。
安装SDK
支持使用DevEco Studio 自动导入和手动导入两种方式,将SDK 导入到您的应用工程中,您可以参考Demo示例工程源码了解如何使用本SDK。
自动导入,使用ohpm从OpenHarmony三方库中心仓安装。
2.0.1版本开始支持从OpenHarmony三方库中心仓 获取SDK
在工程的根目录执行
ohpm install @alidns/httpdnsohpm工具以及更多关于OpenHarmony安装第三方SDK的信息请参考OpenHarmony三方库中心仓说明
手动导入,引用本地HAR包方式集成SDK。
参考SDK下载,获取鸿蒙SDK,并集成SDK在自己的App工程项目中
在工程的oh-package.json5中设置三方包依赖。以HAR包在工程根目录下为例,配置示例如下(实际配置时请以HAR包实际目录为准):
"dependencies": { "@alidns/httpdns": "file:alidns-harmony-sdk-2.0.1.har" }依赖设置完成后,需要执行ohpm install命令安装依赖包,依赖包会存储在工程的oh_modules目录下。
ohpm install
使用SDK
引入头文件
import { Alipdns,schemaType,DNSDomainInfo, DNSLogger } from '@alidns/httpdns'设置鉴权模式
开启鉴权模式,以保障用户身份安全,不被第三方未授权者盗用,用户在Alibity onCreate生命周期回调中执行以下代码配置SDK。
参考创建密钥在控制台创建AccessKey ID 和 AccessKey Secret。
import { Alipdns,schemaType,DNSDomainInfo, DNSLogger } from '@alidns/httpdns'
const AccountID = '这里需要替换为设置您在控制台接入SDK的Account ID';
const AccessKeID = '这里需要替换为您在控制台“接入配置”创建的密钥的 AccessKey ID';
const AccessKeySecret = '这里需要替换为您在控制台“接入配置”创建的密钥的 AccessKey Secret';
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
// ************* 阿里pdns-sdk配置 begin *************
DNSLogger.getInstance().setEnableLogger = true;
let alipdns = Alipdns.getInstance();
alipdns.Init(this.context,AccountID,AccessKeID,AccessKeySecret);
alipdns.setKeepAliveDomains(['*****','*****']);
alipdns.setSchemaType(schemaType.https);
alipdns.preLoadDomains(alipdns.QTYPE_V4,['*****','*****','*****']);
// ************* 阿里pdns-sdk配置 end *************
}
// 省略其它代码
}API介绍
1. Account ID和鉴权
必传参数,您在控制台注册自己的应用后,控制台会为此应用生成唯一标识Account ID,鉴权功能来保障用户身份安全,防止被第三方未授权者盗用。用户请参考创建密钥在控制台创建AccessKey,并在APP中通过如下代码设置:
Alipdns.getInstance().Init(this.context,AccountID,AccessKeID,AccessKeySecret);为避免在日志中泄漏参数Account ID/AccessKey ID/AccessKey Secret或App运行过程中产生的数据,建议线上版本关闭SDK调试日志。
Account ID、AccessKey ID 和 AccessKey Secret此类参数与计量计费密切相关,为防止恶意反编译获取参数造成信息泄露,在生产环境中,您需要避免直接传入明文。例如,您可以预先把明文进行编码或加密处理,在传值的时候再对已编码或加密的明文进行解码或解密。同时,建议您对 app 进行代码混淆处理并加固。否则,您的Account ID、AccessKey ID 和 AccessKey Secret可能会被第三方通过反编译的方式获得。
2. 解析协议设置
SDK支持设置DNS解析请求协议类型,可自主选择通过HTTP或HTTPS协议解析,具体可通过scheme属性进行设置。
SDK默认并推荐使用HTTPS协议进行解析,因为HTTPS协议安全性更好。移动解析HTTPDNS的计费项是按HTTP的解析次数进行收费,其中HTTPS是按5倍HTTP流量进行计费,开发者可以根据自身实际业务需要选择scheme类型。如下设置:
Alipdns.getInstance().setSchemaType(schemaType.https);3. 设置域名缓存保持
SDK在缓存功能已开启的情况下,可设置针对某些域名开启缓存保持功能,如果该功能开启,SDK会自动更新这些域名的过期缓存,保障用户缓存数据及时更新,但是可能会带来域名解析次数和客户端流量消耗的增多。如果不设置该功能,那么SDK不会自动进行过期缓存更新,只有当用户调用解析方法时,才会再次进行缓存更新。若要设置某些域名的缓存保持需要通过以下代码设置:
Alipdns.getInstance().setKeepAliveDomains(['*****','*****']);优势:
可及时(TTL过期前)更新记录。
配合预加载可降低首次解析延迟(0ms)。
劣势:缓存时间超过TTL*75%之后会再重新请求,会带来额外的费用。
4. 预解析
由于SDK可以设置开启缓存功能,在第一次解析完域名产生缓存后,后续再次解析此域名时解析速度可提升至0时延。因此,建议在app启动后,对app中可能要解析的域名进行预解析。
代码示例:
Alipdns.getInstance().preLoadDomains(alipdns.QTYPE_V4,['*****','*****','*****']);5. 设置开启SDK调试日志开关
用户可以设置是否开启SDK调试日志开关(true为开启调试日志,false为关闭调试日志),该方法请在SDK初始化前设置。
DNSLogger.getInstance().setEnableLogger = true;6. 设置是否开启使用 移动解析HTTPDNS 解析失败时自动降级到localdns进行兜底解析
SDK默认开启使用移动解析HTTPDNS解析失败时自动降级到localdns兜底解析
Alipdns.getInstance().setEnableLocalDns(true);//默认开启使用移动解析HTTPDNS解析失败时自动降级到localdns兜底解析7. 设置域名解析的超时时间
timeout属性为域名解析的超时时间。默认超时时间为3s,用户可自定义超时时间,建议设置在2~5s之间。
Alipdns.getInstance().setTimeout(3);//默认超时时间为3s8. 解析方法
SDK提供不同的域名解析方法,示例如下:
/// 异步解析方法
/// Alipdns.getInstance().QTYPE_V4 解析ip地址类型:ipv4
/// host 要解析的域名
/// ips 回调(所有ip地址)
Alipdns.getInstance().getIpsByHostAsync(Alipdns.getInstance().QTYPE_V4, host,(ips:string[]) => {});
/// 同步解析方法(取缓存中的数据)
/// Alipdns.getInstance().QTYPE_V4 解析ip地址类型:ipv4
/// host 要解析的域名
/// true 是否允许返回过期ip结果
const result = Alipdns.getInstance().getIpsByHostFromCache(Alipdns.getInstance().QTYPE_V4,host,true);
如何使用SDK
addCustomDnsRule方式
在发起网络请求之前,调用SDK的域名解析API进行DNS解析,通过connection.addCustomDnsRuleAPI配置DNS的解析结果,为当前应用程序添加自定义host和对应的IP地址的映射。以HTTP请求为例,代码如下:
import { http } from '@kit.NetworkKit';
import connection from '@ohos.net.connection';
import { Alipdns,schemaType,DNSDomainInfo } from '@alidns/httpdns'
import Url from '@ohos.url';
export async function requestWithHttpDns(url: string, options: http.HttpRequestOptions): Promise<http.HttpResponse> {
let urlObject = Url.URL.parseURL(url);
const host = urlObject.hostname;
// ************* 移动解析HTTPDNS解析获取域名 begin *************
const result = Alipdns.getInstance().getIpsByHostFromCache(Alipdns.getInstance().QTYPE_V4,host,true);
// ************* 移动解析HTTPDNS解析获取域名 end *************
// ************* 通过系统API设置DNS规则 begin *************
try {
await connection.removeCustomDnsRule(host);
} catch (ignored) {
}
if (result.length ?? 0 > 0) {
await connection.addCustomDnsRule(host, result);
} else {
console.log(`httpdns解析没有结果,不设置dns`);
}
// ************* 通过系统API设置DNS规则 begin *************
// ************* 通过系统API进行网络请求 begin *************
const httpRequest = http.createHttp();
return httpRequest.request(url, options);
// ************* 通过系统API进行网络请求 end *************
}HarmonyOS 如何定制DNS解析规则
HarmonyOS 提供了定制DNS解析规则的API:addCustomDnsRule、removeCustomDnsRule、clearCustomDnsRules。
通过addCustomDnsRule API应用可以添加自定义host和对应的IP地址的映射,
通过removeCustomDnsRule API应用可以删除对应host的自定义DNS规则,
通过clearCustomDnsRules API应用可以删除所有的自定义DNS规则。
因此,当应用想要定制网络请求的DNS规则时,可以在网络请求之前,通过上述API设置对应的规则,然后再发起网络请求。
Remote Communication Kit的dnsRules方式
当使用Remote Communication Kit包进行网络请求时,可以先调用SDK的域名解析API进行DNS解析,然后通过配置dnsRules字段,修改DNS规则,以fetch请求为例,代码如下:
import { Alipdns,schemaType,DNSDomainInfo } from '@alidns/httpdns'
import { rcp } from '@kit.RemoteCommunicationKit';
import Url from '@ohos.url';
export async function rcpWithHttpDns(url: string): Promise<rcp.Response> {
let urlObject = Url.URL.parseURL(url);
const host = urlObject.hostname;
// ************* 移动解析HTTPDNS解析域名获取IP结果 begin *************
const result = Alipdns.getInstance().getIpsByHostFromCache(Alipdns.getInstance().QTYPE_V4,host,true);
// ************* 移动解析HTTPDNS解析域名获取IP结果 end *************
const request = new rcp.Request(url, "GET");
if (result.length ?? 0 > 0) {
request.configuration = {
dns: {
// ************* 通过dnsRules设置IP begin *************
dnsRules: [{ host, port: 443, ipAddresses: result },{ host, port: 80, ipAddresses: result }]
// ************* 通过dnsRules设置IP end *************
}
}
}
// ************* 通过系统API进行网络请求 begin *************
const session = rcp.createSession();
return session.fetch(request);
// ************* 通过系统API进行网络请求 end *************
}域名解析最佳实践
预解析 + 允许过期回复,实现最佳性能
在对网络性能要求较高的场景中,结合「预解析」与「允许过期回复」策略,可显著提升 DNS 解析速度,甚至实现 “0 时延”解析。
得益于 SDK 内置的缓存机制,在完成预解析后,后续对该域名的解析请求可直接命中缓存,避免网络往返,极大优化用户体验。
1,预解析
启用缓存并预解析关键域名(推荐在 App 启动时执行)
在 EntryAbility 的 onCreate() 中,提前解析业务中使用的域名,将结果缓存至本地内存中。
1,适用于仅支持ipv4的场景
//********适用于仅支持ipv4的场景*******
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate');
let alipdns = Alipdns.getInstance();
alipdns.Init(this.context,AccountID,AccessKeID,AccessKeySecret);
//预解析的IPV4记录类型
alipdns.preLoadDomains(alipdns.QTYPE_V4,['您要预加载的域名1','您要预加载的域名2']);
}2,适用于需要支持ipv6的场景
//********适用于需要支持ipv6的场景*******
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate');
let alipdns = Alipdns.getInstance();
alipdns.Init(this.context,AccountID,AccessKeID,AccessKeySecret);
//预解析的IPV4和IPV6记录类型
alipdns.preLoadDomains(alipdns.QTYPE_Auto,['您要预加载的域名1','您要预加载的域名2']);
}2,允许过期回复
解析时优先使用缓存(允许返回过期 IP),在实际发起网络请求前,优先从缓存中获取 IP 地址,并允许使用已过期但尚未失效的缓存记录。这样即使 TTL 已过,只要缓存未被清除,仍可立即返回结果,实现“零等待”。
1,适用于仅支持ipv4的场景
//********适用于仅支持ipv4的场景*******
// ************* HTTPDNS解析获取域名 begin *************
//解析IPV4记录
let finalIps = await this.resolverHost(Alipdns.getInstance().QTYPE_V4,host);
// ************* HTTPDNS解析获取域名 end *************
/**
* HTTPDNS 域名解析(缓存优先 + 网络兜底)
* @param qtype - DNS 查询类型(如 Alipdns.getInstance().QTYPE_V4 //解析IPV4记录)
* @param host - 目标域名
* @returns 解析成功的 IP 数组
*/
async resolverHost(qtype: string, host: string): Promise<string[]> {
// ************* HTTPDNS解析:缓存 → 网络兜底 *************
let finalIps: string[] = [];
// 1. 优先从缓存获取 IP(参数三为true 允许返回过期但可用的记录)
try {
const cacheResult = Alipdns.getInstance().getIpsByHostFromCache(qtype, host, true);
// 校验缓存结果
if (Array.isArray(cacheResult) && cacheResult.length > 0) {
finalIps = cacheResult;
console.log(`pdns: [缓存命中] 域名 ${host} 解析结果: ${finalIps.join(', ')}`);
} else {
console.log(`pdns: [缓存未命中/无效] 域名 ${host},将发起网络请求`);
}
} catch (e) {
console.warn(`pdns: 缓存查询异常: ${e?.message || e}`);
}
// 2. 缓存无效时,发起网络请求
if (finalIps.length === 0) {
try {
finalIps = await this.getIpsFromNetwork(qtype, host);
if (finalIps.length > 0) {
console.log(`pdns: [网络请求成功] 域名 ${host} 解析结果: ${finalIps.join(', ')}`);
} else {
console.warn(`pdns: [网络请求] 域名 ${host} 返回空结果`);
}
} catch (err) {
console.error(`pdns: [网络请求失败] 域名 ${host}: ${err?.message || JSON.stringify(err)}`);
// 保持 finalIps 为空数组,后续走系统DNS
}
}
return finalIps;
}
// 无缓存时网络请求解析域名获取 IP
getIpsFromNetwork(qtype: string, domain: string): Promise<string[]> {
return new Promise((resolve) => {
Alipdns.getInstance().getIpsByHostAsync(qtype, domain, (ips: string[]) => {
if (Array.isArray(ips)) {
resolve(ips);
} else {
resolve([]);
}
});
});
}2,适用于需要支持ipv6的场景
//********适用于仅支持ipv6的场景*******
// ************* HTTPDNS解析获取域名 begin *************
// 解析IPV4和IPV6记录
let finalIps = await this.resolverHost(Alipdns.getInstance().QTYPE_Auto,host);
// ************* HTTPDNS解析获取域名 end *************
/**
* HTTPDNS 域名解析(缓存优先 + 网络兜底)
* @param qtype - DNS 查询类型(如 Alipdns.getInstance().QTYPE_Auto //解析IPV4和IPV6记录)
* @param host - 目标域名
* @returns 解析成功的 IP 数组
*/
async resolverHost(qtype: string, host: string): Promise<string[]> {
// ************* HTTPDNS解析:缓存 → 网络兜底 *************
let finalIps: string[] = [];
// 1. 优先从缓存获取 IP(参数三为true 允许返回过期但可用的记录)
try {
const cacheResult = Alipdns.getInstance().getIpsByHostFromCache(qtype, host, true);
// 校验缓存结果
if (Array.isArray(cacheResult) && cacheResult.length > 0) {
finalIps = cacheResult;
console.log(`pdns: [缓存命中] 域名 ${host} 解析结果: ${finalIps.join(', ')}`);
} else {
console.log(`pdns: [缓存未命中/无效] 域名 ${host},将发起网络请求`);
}
} catch (e) {
console.warn(`pdns: 缓存查询异常: ${e?.message || e}`);
}
// 2. 缓存无效时,发起网络请求
if (finalIps.length === 0) {
try {
finalIps = await this.getIpsFromNetwork(qtype, host);
if (finalIps.length > 0) {
console.log(`pdns: [网络请求成功] 域名 ${host} 解析结果: ${finalIps.join(', ')}`);
} else {
console.warn(`pdns: [网络请求] 域名 ${host} 返回空结果`);
}
} catch (err) {
console.error(`pdns: [网络请求失败] 域名 ${host}: ${err?.message || JSON.stringify(err)}`);
// 保持 finalIps 为空数组,后续走系统DNS
}
}
return finalIps;
}
// 无缓存时网络请求解析域名获取 IP
getIpsFromNetwork(qtype: string, domain: string): Promise<string[]> {
return new Promise((resolve) => {
Alipdns.getInstance().getIpsByHostAsync(qtype, domain, (ips: string[]) => {
if (Array.isArray(ips)) {
resolve(ips);
} else {
resolve([]);
}
});
});
}自建DNS
从 v2.0.0 版本起,HTTPDNS Harmony SDK 新增对 私有化部署的自建DNS 的支持。
自建DNS模式适用于对数据合规性、解析策略定制有更高要求的场景,例如金融、政务、大型互联网企业等。SDK 支持 纯公有云DNS、纯自建DNS、主备混合(公有云DNS+自建DNS互为兜底) 四种典型部署模式,灵活适配不同业务架构。
核心能力
私有化部署支持:支持通过 IPv4/IPv6 地址或 Host 域名方式配置自建DNS 服务端点。
双向鉴权机制:使用客户专属的
accessKeyId和accessKeySecret进行请求签名,保障通信安全。熔断与健康检查:当某自建DNS 节点连续失败 ≥3 次时自动熔断,后续每分钟使用指定
healthCheckDomain探测其可用性,恢复后自动重新启用。智能降级兜底:当主用 DNS(公有云DNS或自建DNS)解析失败达到阈值时,自动切换至备用 DNS,保障解析高可用。
无缝兼容现有 API:无论使用公有云DNS还是自建DNS,上层调用解析接口的方式完全一致,无需修改业务逻辑。
配置说明
1. 仅使用公有云DNS
适用于未部署自建DNS 的标准 SaaS 用户。
let alipdns = Alipdns.getInstance();
alipdns.Init(this.context,AccountID,AccessKeID,AccessKeySecret);2. 仅使用自建DNS(私有化部署)
适用于完全依赖自建DNS 的客户。
let alipdns = Alipdns.getInstance();
alipdns.InitFusionDNS(this.context,['1.1.X.X','2.2.X.X'],null, null,'443','熔断后健康检查域名','客户私有 accessKeyId','客户私有 accessKeySecret');3. 公有云DNS为主,自建DNS为备
主用阿里云公共 HTTPDNS解析失败后,自动降级到自建DNS。
let alipdns = Alipdns.getInstance();
// 主用:公有云DNS
alipdns.Init(this.context,AccountID,AccessKeID,AccessKeySecret);
// 备用:自建DNS
alipdns.InitFusionDNS(this.context,['1.1.X.X','2.2.X.X'],null, null,'443','熔断后健康检查域名','客户私有 accessKeyId','客户私有 accessKeySecret');4. 自建DNS为主,公有云DNS为备
主用自建DNS 解析失败后,自动降级到阿里云公有云DNS。
let alipdns = Alipdns.getInstance();
// 主用:自建DNS
alipdns.InitFusionDNS(this.context,['1.1.X.X','2.2.X.X'],null, null,'443','熔断后健康检查域名','客户私有 accessKeyId','客户私有 accessKeySecret');
// 备用:公有云DNS
alipdns.Init(this.context,AccountID,AccessKeID,AccessKeySecret);新增服务 API
为支持自建DNS 的私有化部署与高可用容灾,SDK 新增以下三个核心接口,用于配置自建DNS服务、控制安全策略及实现主备自动降级。
1. 配置自建DNS 服务端点与鉴权信息
/**使用私有化部署的自建DNS相关,若只使用公共DNS不需要设置该方法
*
* 设置自建DNS 服务器地址和鉴权信息
* 客户通过此接口传入私有 DNS 服务器的地址和鉴权凭证
* SDK 将使用这些信息发起请求
* @param ctx 上下文
* @param serverIpv4Arr IPv4 地址数组(可为 nil)
* @param serverIpv6Arr IPv6 地址数组(可为 nil)
* @param serverHostArr Host 域名数组(可为 nil)
* @param port 服务端口(如 "443",传 nil 使用默认"443")
* @param healthCheckDomain 熔断后健康检查域名,当某个解析服务连续失败次数大于3次后,会触发熔断,该解析服务ip会进入healthCheck状态 (后续请求不会走该服务),
* 定时器每分钟会使用该healthCheckDomain调用解析接口探测该解析服务是否可以使用,如果探测成功,则恢复alive状态(后续请求可以走该服务)
* @param accessKeyId 客户私有 accessKeyId(用于鉴权)
* @param accessKeySecret 客户私有 accessKeySecret(用于鉴权)
*/
InitFusionDNS(
ctx:Context,
ipv4: string[] | null,
ipv6: string[] | null,
host: string[] | null,
port: string | null,
healthCheckDomain: string,
accessKeyId: string,
accessKeySecret: string
)2. 设置主备 DNS 自动降级阈值
/**公共云DNS和融合云DNS同时配置时,设置主用DNS解析失败多少次后自动降级到备用DNS来兜底,如果只配置一种DNS,不需要设置该方法
*
* 设置主用DNS解析失败多少次后自动降级到备用DNS来兜底,如果只配置一种DNS,不需要设置该方法
* @param fallbackThreshold 次数(主用公共DNS时默认 4,主用融合DNS时默认2)
* 范围[0-4] 设置0表示立即降级,最大4
*/
setFallbackThreshold(fallbackThreshold:number);