This topic describes how to integrate and use HTTPDNS in a Node.js application.
Node.js is a JavaScript runtime environment built on the Chrome V8 engine. It is widely used for server-side development, API building, and implementing the microservices model.
Alibaba Cloud provides the @alicloud-emas/httpdns software development kit (SDK) for the Node.js environment. You can integrate the SDK into your Node.js applications and use HTTPDNS features by following the best practices for Node.js.
The following sections describe how to use the SDK and outline the best practices.
Quick start
1.1 Activate the service
See Quick Start to activate HTTPDNS.
1.2 Obtain configurations
See Development Configurations to obtain your AccountId, SecretKey, and other information from the development configurations section of the EMAS console. This information is required to initialize the SDK.
Installation
Install the SDK using npm:
npm install @alicloud-emas/httpdnsIntegration example:
For sample code and documentation, see the GitHub repository.
Configuration and usage
3.1 Initialize configurations
Initialize the SDK after your application starts to use HTTPDNS features. During initialization, you must configure your AccountId, SecretKey, and feature switches. The following code provides an example:
import { createClient } from '@alicloud-emas/httpdns';
const client = createClient({
accountId: 'your-account-id',
secretKey: 'your-secret-key',
enableExpiredIP: true,
enableHTTPS: true,
});
Setting the enableHTTPS parameter to true increases your billing costs. For more information, see the Product Billing document.
3.1.1 Log configuration
To output HTTPDNS logs during application development, configure a logger during initialization. The following code provides an example:
const client = createClient({
...,
logger: console
});
3.2 Domain name resolution
3.2.1 Synchronous non-blocking resolution (Recommended)
Use the synchronous non-blocking resolution method. This method immediately returns cached results without blocking program execution. The following code provides an example:
function resolve() {
const result = client.getHttpDnsResultForHostSyncNonBlocking('www.aliyun.com');
if (result) {
console.log('Resolution result:', result.ipv4);
console.log('Domain name:', result.domain);
console.log('IPv6:', result.ipv6);
} else {
console.log('Cache miss. Asynchronous resolution in progress...');
// Asynchronous resolution has started in the background. The next call will return the result.
}
}3.2.2 Synchronous resolution
To ensure that you receive a resolution result, use the synchronous resolution method. This method waits for the resolution to complete before proceeding. The following code provides an example:
async function resolve() {
try {
const result = await client.getHttpDnsResultForHostSync('www.aliyun.com');
console.log('Domain name:', result.domain);
console.log('IPv4:', result.ipv4);
console.log('IPv6:', result.ipv6);
} catch (error) {
console.error('Resolution failed:', error);
}
}
Node.js best practices
4.1 How it works
Create a custom DNS lookup function in the application.
For requests that need to be resolved using HTTPDNS, configure them to use the custom lookup function.
In the lookup function, retrieve the requested domain name and resolve it to an IP address using HTTPDNS.
In the lookup function, return the resolved IP address to initiate the actual request. This process avoids using the local DNS for resolution.
4.2 Network library integration
4.2.1 Axios integration
Integrate Axios using an agent. The core steps are as follows:
Step 1: Create a custom lookup function
const dns = require('dns');
function createHTTPDNSLookup(httpdnsClient) {
return (hostname, options, callback) => {
// Standardize parameters
if (typeof options === 'function') {
callback = options;
options = {};
}
// Ensure the callback exists
if (typeof callback !== 'function') {
throw new Error('callback must be a function');
}
// Use HTTPDNS to resolve the domain name
const result = httpdnsClient.getHttpDnsResultForHostSyncNonBlocking(hostname);
if (result) {
const hasIPv4 = result.ipv4 && result.ipv4.length > 0;
const hasIPv6 = result.ipv6 && result.ipv6.length > 0;
if (hasIPv4 || hasIPv6) {
if (options && options.all) {
// Return all IP addresses
const addresses = [
...(hasIPv4 ? result.ipv4.map(ip => ({ address: ip, family: 4 })) : []),
...(hasIPv6 ? result.ipv6.map(ip => ({ address: ip, family: 6 })) : [])
];
console.log(`[DNS Lookup] HTTPDNS resolved successfully: ${hostname} -> Returning all IP addresses (${addresses.length})`);
callback(null, addresses);
} else {
// Prioritize IPv4, then IPv6
if (hasIPv4) {
console.log(`[DNS Lookup] HTTPDNS resolved successfully: ${hostname} -> ${result.ipv4[0]} (IPv4)`);
callback(null, result.ipv4[0], 4);
} else {
console.log(`[DNS Lookup] HTTPDNS resolved successfully: ${hostname} -> ${result.ipv6[0]} (IPv6)`);
callback(null, result.ipv6[0], 6);
}
}
return;
}
}
console.log(`[DNS Lookup] No available IP from HTTPDNS. Falling back to system DNS for: ${hostname}`);
dns.lookup(hostname, options, callback);
};
}Step 2: Create a custom agent
const https = require('https');
const httpsAgent = new https.Agent({
lookup: createHTTPDNSLookup(httpdnsClient),
keepAlive: true,
maxSockets: 10
});
Step 3: Create an Axios instance
const axios = require('axios');
const instance = axios.create({
httpsAgent: httpsAgent,
timeout: 10000
});
// Usage
const response = await instance.get('https://www.aliyun.com');
4.2.2 urllib integration
Integrate urllib using an agent. The core steps are as follows:
Step 1: Create a custom lookup function
const dns = require('dns');
function createHTTPDNSLookup(httpdnsClient) {
return (hostname, options, callback) => {
// Standardize parameters
if (typeof options === 'function') {
callback = options;
options = {};
}
// Ensure the callback exists
if (typeof callback !== 'function') {
throw new Error('callback must be a function');
}
// Use HTTPDNS to resolve the domain name
const result = httpdnsClient.getHttpDnsResultForHostSyncNonBlocking(hostname);
if (result) {
const hasIPv4 = result.ipv4 && result.ipv4.length > 0;
const hasIPv6 = result.ipv6 && result.ipv6.length > 0;
if (hasIPv4 || hasIPv6) {
if (options && options.all) {
// Return all IP addresses
const addresses = [
...(hasIPv4 ? result.ipv4.map(ip => ({ address: ip, family: 4 })) : []),
...(hasIPv6 ? result.ipv6.map(ip => ({ address: ip, family: 6 })) : [])
];
console.log(`[DNS Lookup] HTTPDNS resolved successfully: ${hostname} -> Returning all IP addresses (${addresses.length})`);
callback(null, addresses);
} else {
// Prioritize IPv4, then IPv6
if (hasIPv4) {
console.log(`[DNS Lookup] HTTPDNS resolved successfully: ${hostname} -> ${result.ipv4[0]} (IPv4)`);
callback(null, result.ipv4[0], 4);
} else {
console.log(`[DNS Lookup] HTTPDNS resolved successfully: ${hostname} -> ${result.ipv6[0]} (IPv6)`);
callback(null, result.ipv6[0], 6);
}
}
return;
}
}
console.log(`[DNS Lookup] No available IP from HTTPDNS. Falling back to system DNS for: ${hostname}`);
dns.lookup(hostname, options, callback);
};
}Step 2: Create a custom agent
const urllib = require('urllib');
const https = require('https');
const httpsAgent = new https.Agent({
lookup: createHTTPDNSLookup(httpdnsClient),
keepAlive: true,
maxSockets: 10
});
Step 3: Send a request
async function request(url, options = {}) {
// Select an agent based on the URL type
if (url.startsWith('https://')) {
options.httpsAgent = httpsAgent;
} else {
options.agent = httpAgent; // Create an httpAgent similarly
}
options.timeout = options.timeout || 10000;
try {
return await urllib.request(url, options);
} catch (error) {
// Automatic retry logic
if (isConnectionError(error) && !options._retried) {
options._retried = true;
delete options.httpsAgent; // Retry using the system DNS
return await urllib.request(url, options);
}
throw error;
}
}
API
5.1 Initialization
Initialize the configuration when the application starts.
const { createClient } = require('@alicloud-emas/httpdns');
const client = createClient({
accountId: 'your-account-id',
secretKey: 'your-secret-key',
timeout: 5000, // Resolution timeout in milliseconds
maxRetries: 1, // Maximum number of retries
enableHTTPS: false, // Specifies whether to use HTTPS
enableCache: true, // Specifies whether to cache IP addresses
enableExpiredIP: true, // Specifies whether to allow the use of expired IP addresses
});
Parameters:
Parameter | Type | Required | Features |
accountId | String | Required parameters | AccountId |
secretKey | String | Optional parameters | Signing key |
bootstrapIPs | Array | Optional parameters | List of bootstrap IP addresses |
timeout | Number | Optional parameters | Resolution timeout |
maxRetries | Number | Optional parameters | Maximum number of retries |
enableHTTPS | Boolean | Optional Parameters | Specifies whether to use HTTPS |
enableCache | Boolean | Optional parameters | Specifies whether to cache IP addresses |
logger | Object | Optional parameters | Logger |
enableExpiredIP | Boolean | Optional parameters | Specifies whether to allow the use of expired IP addresses |
Setting the enableHTTPS parameter to true increases your billing costs. For more information, see the Product Billing document.
5.2 Pre-resolve domain names
Set a list of domain names to pre-resolve. This allows the SDK to resolve them in advance and reduces the latency of subsequent resolution requests.
// Set the pre-resolution list
client.setPreResolveHosts(['www.aliyun.com']);
5.3 Synchronous non-blocking resolution
Resolve a specified domain name. This method immediately returns cached results without blocking the process.
const result = client.getHttpDnsResultForHostSyncNonBlocking('www.aliyun.com');
if (result) {
console.log('Cached result:', result.ipv4);
}
Parameters:
Parameter | Type | Required | Features |
domain | String | Required parameters | Domain name |
options | Object | Optional parameters | Resolution options |
Description of the returned JSON fields:
Field | Type | Features |
domain | String | Domain name |
ipv4 | Array | List of IPv4 addresses |
ipv6 | Array | List of IPv6 addresses |
ipv4Ttl | Number | IPv4 expiration time |
ipv6Ttl | Number | IPv6 expiration time |
ipv4Timestamp | Date | IPv4 resolution timestamp |
ipv6Timestamp | Date | IPv6 resolution timestamp |
5.4 Synchronous resolution
Synchronously resolve a specified domain name.
const result = await client.getHttpDnsResultForHostSync('www.aliyun.com');
console.log('Resolution result:', result);
5.5 Client management
Retrieve the client status and manage the client lifecycle.
// Check the client's health status
const isHealthy = client.isHealthy();
// Get the current list of service IP addresses
const serviceIPs = client.getServiceIPs();
// Manually update the service IP addresses
await client.updateServiceIPs();
// Shut down the client
await client.close();
Summary
This topic described how to use the HTTPDNS SDK in a Node.js environment and provided best practices. Integrating the SDK with network libraries using an agent helps you achieve high-performance, high-availability domain name resolution. The main features are as follows:
Easy to use: Provides simple API operations and supports both synchronous and synchronous non-blocking resolution.
High availability: Supports failover and downgrade policies to ensure service stability.
Performance optimization: Includes a built-in caching mechanism and connection reuse to improve resolution efficiency.
Secure and reliable: Supports authenticated resolution and HTTPS communication to ensure data security.
Follow the best practices in this topic to efficiently integrate the HTTPDNS service into your Node.js applications.