Integrate and use the HTTPDNS HarmonyOS SDK for domain resolution, DNS acceleration, and anti-hijacking.
Install the SDK
Import the SDK into your DevEco Studio project by automatic import or manual import. For a complete example, download the Demo sample project source code.
-
Automatic import: Install by using ohpm
You can get the SDK from the OpenHarmony third-party library repository.
Run the following command in your project root:
ohpm install @alidns/httpdnsThe Instructions for the OpenHarmony Third-Party Library Repository covers ohpm usage and third-party SDK installation.
-
Manual import: Reference the local HAR package
Download the HarmonyOS SDK from the SDK Download page and integrate it into your app project.
In your project's
oh-package.json5file, set the dependency. The following example shows the configuration if the HAR package is in the root directory of the project. Use the actual path to your HAR package."dependencies": { "@alidns/httpdns": "file:alidns-harmony-sdk-2.0.4.har" }After configuring the dependency, run
ohpm install. The package is stored in the oh_modules directory.ohpm install
Use the SDK
Import the module
import { Alipdns,schemaType,DNSDomainInfo, DNSLogger } from '@alidns/httpdns'
Set up authentication
Add the following code in your ability's onCreate callback to enable authentication:
Create an AccessKey ID and AccessKey Secret on the console by following Create a key.
import { Alipdns,schemaType,DNSDomainInfo, DNSLogger } from '@alidns/httpdns'
const AccountID = 'TODO: Replace with your Account ID from the console.';
const AccessKeyID = 'TODO: Replace with the AccessKey ID of the key you created in the "Access Configuration" section of the console.';
const AccessKeySecret = 'TODO: Replace with the AccessKey Secret of the key you created in the "Access Configuration" section of the console.';
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
// ************* Alibaba Cloud HTTPDNS SDK configuration - START *************
DNSLogger.getInstance().setEnableLogger = true;
let alipdns = Alipdns.getInstance();
alipdns.Init(this.context,AccountID,AccessKeyID,AccessKeySecret);
alipdns.setKeepAliveDomains(['your-domain-1.com','your-domain-2.com']);
alipdns.setSchemaType(schemaType.https);
alipdns.preLoadDomains(alipdns.QTYPE_V4,['your-domain-1.com','your-domain-2.com','your-domain-3.com']);
// ************* Alibaba Cloud HTTPDNS SDK configuration - END *************
}
// Other code omitted
}
API
1. Account ID and authentication
The Account ID is required. After you register your application on the console, a unique Account ID is generated. Create an AccessKey ID and AccessKey Secret by following Create a key, and set them in your app:
Alipdns.getInstance().Init(this.context,AccountID,AccessKeyID,AccessKeySecret);
-
Disable SDK debug logs in production to prevent credentials and runtime data from leaking into logs.
-
Account ID, AccessKey ID, and AccessKey Secret are tied to metering and billing. To prevent credential theft through decompilation, avoid passing them as plaintext in production. Encode or encrypt the credentials and decrypt them only when passing them to the SDK. We also recommend code obfuscation and hardening to prevent third parties from extracting these credentials.
2. Resolution protocol
Set the resolution protocol (HTTP or HTTPS) with the scheme property.
The SDK defaults to HTTPS, recommended for security. HTTPDNS bills by resolution request count, with HTTPS requests billed at 5x the HTTP rate. Choose a scheme based on your requirements:
Alipdns.getInstance().setSchemaType(schemaType.https);
3. Automatic cache refresh
Automatic cache refresh keeps cached entries current for specified domains. When enabled, the SDK proactively updates expired entries, which may increase resolution requests and traffic. When disabled, cache updates occur only when your app calls a resolution method.
Alipdns.getInstance().setKeepAliveDomains(['your-domain-1.com','your-domain-2.com']);
-
Pros:
-
Updates records before the TTL expires.
-
Reduces first-resolution latency to 0 ms when combined with pre-resolution.
-
-
Cons: If a cached entry's age exceeds 75% of its TTL, the SDK sends a new request, which incurs additional costs.
4. Pre-resolution
After the first resolution populates the cache, subsequent lookups have zero latency. Pre-resolve domains your app needs at startup.
Example:
Alipdns.getInstance().preLoadDomains(alipdns.QTYPE_V4,['your-domain-1.com','your-domain-2.com','your-domain-3.com']);
5. SDK debug logs
Enable or disable SDK debug logs by setting the value to true or false. Call this method before SDK initialization.
DNSLogger.getInstance().setEnableLogger = true;
6. HTTPDNS to local DNS
By default, the SDK falls back to local DNS when HTTPDNS resolution fails.
Alipdns.getInstance().setEnableLocalDns(true);// By default, fallback to local DNS is enabled if HTTPDNS resolution fails.
7. Resolution timeout
The timeout property sets the domain resolution timeout. Default: 3 seconds. Recommended range: 2–5 seconds.
Alipdns.getInstance().setTimeout(3);// The default timeout is 3 seconds.
8. Immutable cache
Alipdns.getInstance().setImmutableCacheEnable(false);// By default, immutable cache is disabled.
The SDK provides three cache update mechanisms:
-
Immutable cache: The cache stays valid for the app's entire runtime with no expiration checks or updates, minimizing resolution requests.
To enable:
Alipdns.getInstance().setImmutableCacheEnable(true) -
Proactive cache refresh: Keeps cached records fresh with low latency when authoritative records change. Supports up to 10 domains.
To configure:
Alipdns.getInstance().setKeepAliveDomains(['your-domain-1.com','your-domain-2.com']); -
Passive cache update: The cache is passively updated when you call the following resolution methods:
-
Alipdns.getInstance().getIpsByHostAsync(Alipdns.getInstance().QTYPE_V4, host,(ips:string[]) => {});: This method gets an array of resolved IPv4 addresses for a domain. If a valid, non-expired entry exists in the cache, the method returns the cached result. Otherwise, it requests the latest result, returns it, and updates the cache. -
const result = Alipdns.getInstance().getIpsByHostFromCache(Alipdns.getInstance().QTYPE_V4,host,true);: This method gets the IPv4 resolution result from the cache. Its behavior depends on theenableparameter.If
enableis set toYES, a stale record is returned even if the cache is expired (if the cache is empty,nullis returned), and the cache is updated by an asynchronous request. If it is set toNO,nullis returned if the cache is expired or empty, and the cache is updated by an asynchronous request.
-
9. Resolution methods
The SDK provides the following resolution methods:
/**
* Asynchronously resolves a domain name.
* If a valid, non-expired entry exists in the cache, this method returns the cached result.
* If the cache is empty or the entry is expired, it sends a network request to the server, returns the new result to the user, and updates the cache.
* @param qType The query type. QTYPE_V4 for IPv4, QTYPE_V6 for IPv6, or QTYPE_Auto for both.
* @param domain The host to resolve, for example, www.example.com.
* @param callback A callback function that receives an array of resolved IP addresses.
*/
Alipdns.getInstance().getIpsByHostAsync(Alipdns.getInstance().QTYPE_V4, host,(ips:string[]) => {});
/**
* Synchronously retrieves resolution data from the cache.
* If the cache is empty, this method immediately returns null and triggers an asynchronous query to populate the cache.
* If the cache contains a result and expired results are allowed, it returns the stale IP addresses and triggers an asynchronous update.
* If expired results are not allowed and the cache is expired, it returns null and triggers an asynchronous update.
* @param qType The query type. QTYPE_V4 for IPv4, QTYPE_V6 for IPv6, or QTYPE_Auto for both.
* @param domain The host to resolve, for example, www.example.com.
* @param isAllowExp Specifies whether to allow the method to return expired resolution data.
* @returns An array of IP addresses from the cache for the specified host.
*/
const result = Alipdns.getInstance().getIpsByHostFromCache(Alipdns.getInstance().QTYPE_V4,host,true);
Integrate with network requests
Use addCustomDnsRule
Resolve the domain with the SDK, then apply the result with the connection.addCustomDnsRule API to set a custom host-to-IP mapping. Example HTTP request:
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;
// ************* Use HTTPDNS to resolve the domain name - START *************
const result = Alipdns.getInstance().getIpsByHostFromCache(Alipdns.getInstance().QTYPE_V4,host,true);
// ************* Use HTTPDNS to resolve the domain name - END *************
// ************* Set DNS rules by using the system API - START *************
try {
await connection.removeCustomDnsRule(host);
} catch (ignored) {
}
if (result.length ?? 0 > 0) {
await connection.addCustomDnsRule(host, result);
} else {
console.log(`HTTPDNS resolution returned no result. DNS rule is not set.`);
}
// ************* Set DNS rules by using the system API - END *************
// ************* Initiate a network request by using the system API - START *************
const httpRequest = http.createHttp();
return httpRequest.request(url, options);
// ************* Initiate a network request by using the system API - END *************
}
Custom DNS rules in HarmonyOS
HarmonyOS provides these APIs to customize DNS resolution rules: addCustomDnsRule, removeCustomDnsRule, and clearCustomDnsRules.
addCustomDnsRule adds a custom host-to-IP mapping.
removeCustomDnsRule deletes the rule for a specified host.
clearCustomDnsRules deletes all custom DNS rules.
Set these rules before you initiate network requests.
dnsRules with Remote Communication Kit
To use HTTPDNS with the Remote Communication Kit, resolve the domain first, then configure the dnsRules field. Example fetch request:
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;
// ************* Use HTTPDNS to resolve the domain and get the IP addresses - START *************
const result = Alipdns.getInstance().getIpsByHostFromCache(Alipdns.getInstance().QTYPE_V4,host,true);
// ************* Use HTTPDNS to resolve the domain and get the IP addresses - END *************
const request = new rcp.Request(url, "GET");
if (result.length ?? 0 > 0) {
request.configuration = {
dns: {
// ************* Set IP addresses by using dnsRules - START *************
dnsRules: [{ host, port: 443, ipAddresses: result },{ host, port: 80, ipAddresses: result }]
// ************* Set IP addresses by using dnsRules - END *************
}
}
}
// ************* Initiate a network request by using the system API - START *************
const session = rcp.createSession();
return session.fetch(request);
// ************* Initiate a network request by using the system API - END *************
}
Domain resolution best practices
Combine pre-resolution with expired responses for optimal performance.
Combining pre-resolution with expired cache entries achieves near-zero-latency resolution. Cached results serve subsequent requests without network round-trips.
1. Pre-resolution
Pre-resolve critical domains at app startup.
In the onCreate() method of EntryAbility, resolve your service domains and cache them in memory.
1. IPv4 only
// For IPv4-only scenarios
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate');
let alipdns = Alipdns.getInstance();
alipdns.Init(this.context,AccountID,AccessKeyID,AccessKeySecret);
// Pre-resolve A records (IPv4).
alipdns.preLoadDomains(alipdns.QTYPE_V4,['your-domain-to-preload-1.com','your-domain-to-preload-2.com']);
}
2. IPv4 and IPv6
// For scenarios that require IPv6 support
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate');
let alipdns = Alipdns.getInstance();
alipdns.Init(this.context,AccountID,AccessKeyID,AccessKeySecret);
// Pre-resolve A and AAAA records (IPv4 and IPv6).
alipdns.preLoadDomains(alipdns.QTYPE_Auto,['your-domain-to-preload-1.com','your-domain-to-preload-2.com']);
}
2. Allow expired responses
Prioritize the cache and allow expired records. Even after TTL expiration, cached results return immediately, achieving zero-wait resolution.
1. IPv4 only
// For IPv4-only scenarios
// ************* Use HTTPDNS to resolve the domain name - START *************
// Resolve A records (IPv4).
let finalIps = await this.resolverHost(Alipdns.getInstance().QTYPE_V4,host);
// ************* Use HTTPDNS to resolve the domain name - END *************
/**
* HTTPDNS domain resolution (cache-first with network fallback)
* @param qtype - The DNS query type, such as Alipdns.getInstance().QTYPE_V4 for A records.
* @param host - The destination domain.
* @returns An array of successfully resolved IP addresses.
*/
async resolverHost(qtype: string, host: string): Promise<string[]> {
// ************* HTTPDNS resolution: Cache with network fallback *************
let finalIps: string[] = [];
// 1. Prioritize retrieving the IP address from the cache. The third parameter is set to true to allow returning expired but available records.
try {
const cacheResult = Alipdns.getInstance().getIpsByHostFromCache(qtype, host, true);
// Validate the cache result.
if (Array.isArray(cacheResult) && cacheResult.length > 0) {
finalIps = cacheResult;
console.log(`pdns: [Cache hit] Domain ${host} resolved to: ${finalIps.join(', ')}`);
} else {
console.log(`pdns: [Cache miss/invalid] Domain ${host}. Initiating network request.`);
}
} catch (e) {
console.warn(`pdns: Cache query exception: ${e?.message || e}`);
}
// 2. If the cache is invalid, initiate a network request.
if (finalIps.length === 0) {
try {
finalIps = await this.getIpsFromNetwork(qtype, host);
if (finalIps.length > 0) {
console.log(`pdns: [Network request successful] Domain ${host} resolved to: ${finalIps.join(', ')}`);
} else {
console.warn(`pdns: [Network request] Domain ${host} returned an empty result.`);
}
} catch (err) {
console.error(`pdns: [Network request failed] Domain ${host}: ${err?.message || JSON.stringify(err)}`);
// Keep finalIps as an empty array and fall back to the system DNS.
}
}
return finalIps;
}
// If no cache is available, send a network request to resolve the domain and get the IP address.
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. IPv4 and IPv6
// For scenarios that require IPv6 support
// ************* Use HTTPDNS to resolve the domain name - START *************
// Resolve A and AAAA records (IPv4 and IPv6).
let finalIps = await this.resolverHost(Alipdns.getInstance().QTYPE_Auto,host);
// ************* Use HTTPDNS to resolve the domain name - END *************
/**
* HTTPDNS domain resolution (cache-first with network fallback)
* @param qtype - The DNS query type, such as Alipdns.getInstance().QTYPE_Auto for A and AAAA records.
* @param host - The destination domain.
* @returns An array of successfully resolved IP addresses.
*/
async resolverHost(qtype: string, host: string): Promise<string[]> {
// ************* HTTPDNS resolution: Cache with network fallback *************
let finalIps: string[] = [];
// 1. Prioritize retrieving the IP address from the cache. The third parameter is set to true to allow returning expired but available records.
try {
const cacheResult = Alipdns.getInstance().getIpsByHostFromCache(qtype, host, true);
// Validate the cache result.
if (Array.isArray(cacheResult) && cacheResult.length > 0) {
finalIps = cacheResult;
console.log(`pdns: [Cache hit] Domain ${host} resolved to: ${finalIps.join(', ')}`);
} else {
console.log(`pdns: [Cache miss/invalid] Domain ${host}. Initiating network request.`);
}
} catch (e) {
console.warn(`pdns: Cache query exception: ${e?.message || e}`);
}
// 2. If the cache is invalid, initiate a network request.
if (finalIps.length === 0) {
try {
finalIps = await this.getIpsFromNetwork(qtype, host);
if (finalIps.length > 0) {
console.log(`pdns: [Network request successful] Domain ${host} resolved to: ${finalIps.join(', ')}`);
} else {
console.warn(`pdns: [Network request] Domain ${host} returned an empty result.`);
}
} catch (err) {
console.error(`pdns: [Network request failed] Domain ${host}: ${err?.message || JSON.stringify(err)}`);
// Keep finalIps as an empty array and fall back to the system DNS.
}
}
return finalIps;
}
// If no cache is available, send a network request to resolve the domain and get the IP address.
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([]);
}
});
});
}
On-premises DNS
The HTTPDNS HarmonyOS SDK v2.0.0 and later supports on-premises DNS deployment.
On-premises DNS suits scenarios requiring data compliance and custom resolution policies, such as finance, government, and large-scale web services. The SDK supports four deployment modes: public cloud only, on-premises only, and two hybrid primary/standby configurations.
Core capabilities
-
Private deployment: Configure endpoints with IPv4, IPv6, or hostnames.
-
Mutual authentication: Requests are signed with customer-specific
accessKeyIdandaccessKeySecret. -
Circuit breaking and health check: After three consecutive failures, the SDK triggers circuit breaking and probes the node every minute using the
healthCheckDomain. The node is re-enabled after recovery. -
Intelligent fallback: The SDK switches to the standby DNS after the primary exceeds the failure threshold, ensuring high availability.
-
Seamless API compatibility: The resolution API is identical for public cloud and on-premises DNS. No business logic changes required.
Configuration
1. Public cloud DNS only
For standard SaaS users without on-premises DNS.
let alipdns = Alipdns.getInstance();
alipdns.Init(this.context,AccountID,AccessKeyID,AccessKeySecret);
2. On-premises DNS only
For customers who rely entirely on on-premises DNS.
let alipdns = Alipdns.getInstance();
alipdns.InitFusionDNS(this.context,['1.1.X.X','2.2.X.X'],null, null,'443','your-health-check-domain.com','your-private-accessKeyId','your-private-accessKeySecret');
3. Public cloud primary, on-premises standby
Falls back to on-premises DNS when Alibaba Cloud public cloud DNS resolution fails.
let alipdns = Alipdns.getInstance();
// Primary: public cloud DNS
alipdns.Init(this.context,AccountID,AccessKeyID,AccessKeySecret);
// Standby: on-premises DNS
alipdns.InitFusionDNS(this.context,['1.1.X.X','2.2.X.X'],null, null,'443','your-health-check-domain.com','your-private-accessKeyId','your-private-accessKeySecret');
4. On-premises primary, public cloud standby
Falls back to Alibaba Cloud public cloud DNS when on-premises DNS resolution fails.
let alipdns = Alipdns.getInstance();
// Primary: on-premises DNS
alipdns.InitFusionDNS(this.context,['1.1.X.X','2.2.X.X'],null, null,'443','your-health-check-domain.com','your-private-accessKeyId','your-private-accessKeySecret');
// Standby: public cloud DNS
alipdns.Init(this.context,AccountID,AccessKeyID,AccessKeySecret);
New service APIs
The SDK provides these APIs for on-premises DNS configuration, security, and automatic primary/standby fallback.
1. On-premises DNS endpoints and credentials
/** This method is for private deployments that use on-premises DNS. You do not need to call this method if you use only public DNS.
*
* Sets the server addresses and authentication credentials for the on-premises DNS.
* You pass the addresses and credentials of your on-premises DNS servers through this API.
* The SDK uses this information to initiate requests.
* @param ctx The context.
* @param serverIpv4Arr An array of IPv4 addresses. This can be null.
* @param serverIpv6Arr An array of IPv6 addresses. This can be null.
* @param serverHostArr An array of hostnames. This can be null.
* @param port The service port, such as "443". If you pass null, the default port "443" is used.
* @param healthCheckDomain The domain for health checks after circuit breaking. When a resolution service fails more than three consecutive times, circuit breaking is triggered, and the service's IP address enters the healthCheck state. Subsequent requests are not routed to this service.
* A timer then probes the service every minute by resolving the healthCheckDomain. If a probe succeeds, the IP address is marked as available and can receive requests again.
* @param accessKeyId The private AccessKey ID for authentication.
* @param accessKeySecret The private AccessKey Secret for authentication.
*/
InitFusionDNS(
ctx:Context,
ipv4: string[] | null,
ipv6: string[] | null,
host: string[] | null,
port: string | null,
healthCheckDomain: string,
accessKeyId: string,
accessKeySecret: string
)
2. Automatic fallback threshold
/** Use this method to set the failure threshold that triggers an automatic fallback from the primary to the standby DNS. This method is only needed if you have configured both public cloud and on-premises DNS.
*
* @param fallbackThreshold The number of failures. The default is 4 if the primary is a public cloud DNS, and 2 if the primary is an on-premises DNS.
* Valid values: 0 to 4. A value of 0 indicates an immediate fallback.
*/
setFallbackThreshold(fallbackThreshold:number);