Go SDK Integration Guide

Updated at:

This topic explains how to integrate HTTPDNS using the Go SDK. For the basic principles of HTTPDNS integration, see Client Integration Overview.

1. Quick Start

1.1 Enable the Service

You can enable HTTPDNS by following the Quick Start.

1.2 Get Configuration Information

In the EMAS console, go to Development Settings and obtain your AccountId, SecretKey, and AESSecretKey. For more information, see Development Settings. You need these values to initialize the SDK.

2. Installation

You can install the SDK using `go get`:

go get github.com/aliyun/alicloud-httpdns-go-sdk/pkg/httpdns

Integration examples:

See the sample code and documentation in the GitHub repository.

3. Configure and Use the SDK

3.1 Initialization Configuration

You must initialize the SDK after your application starts and before you can use HTTPDNS features. During initialization, set parameters such as AccountId and SecretKey, and enable or disable features. Example:

package main

import (
    "context"
    "log"
    "os"

    "github.com/aliyun/alicloud-httpdns-go-sdk/pkg/httpdns"
)

func main() {
    config := httpdns.DefaultConfig()
    config.AccountID = "your-account-id"
    config.SecretKey = "your-secret-key"  // Optional. Required for authenticated resolution.
    config.EnableHTTPS = true             // Set to true to use HTTPS.

    client, err := httpdns.NewClient(config)
    if err != nil {
        log.Fatal(err)
    }
    defer client.Close()
}
Important

If you set EnableHTTPS to true, your billing increases. Carefully read the Product Billing document.

3.1.1 Configure Logging

To log HTTPDNS events during development, configure a Logger when initializing the SDK. Example:

config := httpdns.DefaultConfig()
config.Logger = log.New(os.Stdout, "[HTTPDNS] ", log.LstdFlags)

3.2 Resolve Domain Names

3.2.1 Synchronous Resolution

The synchronous method first returns cached results. If no cache hit occurs, the method sends an HTTP request. Example:

func resolve(client httpdns.Client) {
    ctx := context.Background()
    result, err := client.Resolve(ctx, "www.aliyun.com")
    if err != nil {
        log.Printf("Resolution failed: %v", err)
        return
    }
    
    log.Printf("Domain: %s", result.Domain)
    log.Printf("IPv4: %v", result.IPv4)
    log.Printf("IPv6: %v", result.IPv6)
    log.Printf("TTL: %v", result.TTL)
}

3.2.2 Asynchronous Resolution

You can use asynchronous resolution for non-blocking calls. The callback function returns the result. Example:

func asyncResolve(client httpdns.Client) {
    ctx := context.Background()
    client.ResolveAsync(ctx, "www.aliyun.com", func(result *httpdns.ResolveResult, err error) {
        if err != nil {
            log.Printf("Asynchronous resolution failed: %v", err)
            return
        }
        log.Printf("Asynchronous resolution result: %s -> %v", result.Domain, result.IPv4)
    })
}

3.2.3 Batch Resolution

You can use batch resolution to resolve multiple domain names at once. Example:

func batchResolve(client httpdns.Client) {
    ctx := context.Background()
    domains := []string{"www.aliyun.com", "www.taobao.com", "www.tmall.com"}
    
    results, err := client.ResolveBatch(ctx, domains)
    if err != nil {
        log.Printf("Batch resolution failed: %v", err)
        return
    }
    
    for _, result := range results {
        log.Printf("Domain: %s, IPv4: %v", result.Domain, result.IPv4)
    }
}
Note

Each batch resolution supports up to five domain names. Requests that include more than five domains return an error.

4. Go Best Practices

Customize the DialContext function to integrate HTTPDNS resolution seamlessly into the standard net/http client. This integration supports both HTTP and HTTPS requests.

Step 1: Create an HTTPDNS Client

package main

import (
    "context"
    "fmt"
    "log"
    "net"
    "net/http"
    "os"
    "time"

    "github.com/aliyun/alicloud-httpdns-go-sdk/pkg/httpdns"
)

func main() {
    // Create an HTTPDNS client.
    config := httpdns.DefaultConfig()
    config.AccountID = "your-account-id"
    config.SecretKey = "your-secret-key"
    config.Logger = log.New(os.Stdout, "[HTTPDNS] ", log.LstdFlags)
    
    dnsClient, err := httpdns.NewClient(config)
    if err != nil {
        log.Fatal(err)
    }
    defer dnsClient.Close()
    
    // Create an HTTP client that uses HTTPDNS.
    httpClient := createHTTPDNSClient(dnsClient)
    
    // Send a request.
    resp, err := httpClient.Get("https://www.aliyun.com")
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()
    
    fmt.Printf("Status: %s\n", resp.Status)
}

Step 2: Create a Custom HTTP Client

func createHTTPDNSClient(dnsClient httpdns.Client) *http.Client {
    return &http.Client{
        Timeout: 30 * time.Second,
        Transport: &http.Transport{
            DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
                // Parse the host and port.
                host, port, err := net.SplitHostPort(addr)
                if err != nil {
                    return nil, err
                }
                
                // Resolve the domain name using HTTPDNS.
                result, err := dnsClient.Resolve(ctx, host)
                if err != nil {
                    log.Printf("[DNS Lookup] HTTPDNS resolution failed. Falling back to system DNS: %s, error: %v", host, err)
                    return net.Dial(network, addr)
                }
                
                // Prefer IPv4.
                var resolvedIP string
                if len(result.IPv4) > 0 {
                    resolvedIP = result.IPv4[0].String()
                    log.Printf("[DNS Lookup] HTTPDNS resolution succeeded: %s -> %s (IPv4)", host, resolvedIP)
                } else if len(result.IPv6) > 0 {
                    resolvedIP = result.IPv6[0].String()
                    log.Printf("[DNS Lookup] HTTPDNS resolution succeeded: %s -> %s (IPv6)", host, resolvedIP)
                } else {
                    log.Printf("[DNS Lookup] HTTPDNS returned no IP addresses. Falling back to system DNS: %s", host)
                    return net.Dial(network, addr)
                }
                
                // Connect using the resolved IP address.
                return net.Dial(network, net.JoinHostPort(resolvedIP, port))
            },
            MaxIdleConns:        100,
            IdleConnTimeout:     90 * time.Second,
            DisableCompression:  false,
        },
    }
}

5. API Reference

5.1 Initialization

The configuration is initialized when the application starts.

config := httpdns.DefaultConfig()
config.AccountID = "your-account-id"
config.SecretKey = "your-secret-key"

client, err := httpdns.NewClient(config)
if err != nil {
    log.Fatal(err)
}
defer client.Close()

Parameters:

Parameter Name

Type

Is it required?

feature

AccountID

string

Required parameters

Account ID

SecretKey

string

Optional parameters

Signing key

BootstrapIPs

[]string

Optional parameter

A list of bootstrap IP addresses.

Timeout

time.Duration

Optional parameters

Resolution timeout. Default: 5 seconds.

MaxRetries

int

Optional parameters

Maximum number of retries. Default: 0.

EnableHTTPS

bool

Optional parameters

Set to true to use HTTPS. Default: false.

EnableMetrics

bool

Optional parameters

Set to true to enable metrics collection. Default: false.

EnableMemoryCache

bool

Optional parameter

Set to true to enable memory caching. Default: true.

EnablePersistentCache

bool

Optional parameters

Set to true to enable persistent caching. Default: false.

AllowExpiredCache

bool

Optional parameters

Set to true to allow expired cache entries. Default: false.

CacheExpireThreshold

time.Duration

Optional parameters

Expiration threshold for persistent cache entries. Default: 0.

Logger

Logger

Optional parameters

Logger

5.2 Resolve a Domain Name

Resolves a specified domain name.

ctx := context.Background()
result, err := client.Resolve(ctx, "www.aliyun.com")
if err != nil {
    log.Printf("Resolution failed: %v", err)
    return
}

fmt.Printf("IPv4: %v\n", result.IPv4)
fmt.Printf("IPv6: %v\n", result.IPv6)

Parameters:

Parameter Name

Type

Required

Features

ctx

context.Context

Required parameter

The context for the operation.

domain

string

This parameter is required.

domain name

opts

...ResolveOption

Optional parameters

Resolution options.

Resolution options:

Option Function

Features

WithIPv4Only()

Resolve IPv4 addresses only.

WithIPv6Only()

Resolve IPv6 addresses only.

WithBothIP()

Resolve both IPv4 and IPv6 addresses.

WithTimeout(duration)

Set the timeout duration.

WithClientIP(ip)

Set the client IP address for proximity-based routing.

Return fields:

Field name

Type

Features

Domain

string

The domain name.

ClientIP

string

The client IP address.

IPv4

[]net.IP

A list of IPv4 addresses.

IPv6

[]net.IP

A list of IPv6 addresses.

TTL

time.Duration

The time-to-live value.

Source

ResolveSource

Parsing source

Timestamp

time.Time

Parsing timestamps

5.3 Batch Resolution

Resolves multiple domain names at once.

ctx := context.Background()
domains := []string{"www.aliyun.com", "www.taobao.com"}
results, err := client.ResolveBatch(ctx, domains)
if err != nil {
    log.Printf("Batch resolution failed: %v", err)
    return
}

for _, result := range results {
    fmt.Printf("Domain: %s, IPv4: %v\n", result.Domain, result.IPv4)
}

Parameters:

Parameter Name

Type

Is this required?

Features

ctx

context.Context

Required parameters

The context for the operation.

domains

[]string

Required parameter

A list of domain names. Maximum: 5.

opts

...ResolveOption

Optional parameter

Resolution options.

5.4 Asynchronous Resolution

Resolves domain names asynchronously. The callback function returns the result.

ctx := context.Background()
client.ResolveAsync(ctx, "www.aliyun.com", func(result *httpdns.ResolveResult, err error) {
    if err != nil {
        log.Printf("Asynchronous resolution failed: %v", err)
        return
    }
    fmt.Printf("Resolution result: %v\n", result.IPv4)
})

Parameters:

Parameter name

Type

Required

feature

ctx

context.Context

Required parameters

The context for the operation.

domain

string

Required parameters

The domain name to resolve.

callback

func(*ResolveResult, error)

Required parameters

The callback function.

opts

...ResolveOption

Optional parameters

Resolution options.

5.5 Client Management

Checks the client status and manages its lifecycle.

// Check client health.
isHealthy := client.IsHealthy()

// Get the current service IP addresses.
serviceIPs := client.GetServiceIPs()

// Manually update service IP addresses.
err := client.UpdateServiceIPs(ctx)

// Get metrics.
stats := client.GetMetrics()
fmt.Printf("Total resolutions: %d\n", stats.TotalResolves)
fmt.Printf("Success rate: %.2f%%\n", stats.SuccessRate*100)
fmt.Printf("Average latency: %v\n", stats.AvgLatency)

// Reset metrics.
client.ResetMetrics()

// Close the client.
err := client.Close()

6. Summary

This topic describes how to use the HTTPDNS Go SDK and best practices for integrating it into your applications. By customizing DialContext, you can integrate HTTPDNS into your HTTP client to achieve high-performance and highly available domain name resolution. Key features include the following:

  1. Easy to use: Provides synchronous, asynchronous, and batch domain name resolution APIs.

  2. High availability: Includes built-in caching and fallback strategies.

  3. Secure and reliable: Supports authenticated domain name resolution and HTTPS communication.

Follow the best practices in this topic to efficiently integrate HTTPDNS into your Go applications.