通过客户端接入概述您已经了解了HTTPDNS接入的基本原理,本文介绍通过Go SDK接入HTTPDNS的方法。
一、快速入门
1.1 开通服务
请参考快速入门开通HTTPDNS。
1.2 获取配置
请参考开发配置在EMAS控制台开发配置中获取AccountId/SecretKey/AESSecretKey等信息,用于初始化SDK。
二、安装
通过go get安装:
go get github.com/aliyun/alicloud-httpdns-go-sdk/pkg/httpdns接入示例:
参考 GitHub仓库中的示例代码和文档。
三、配置和使用
3.1 初始化配置
应用启动后,需要先初始化SDK,才能调用HTTPDNS能力。初始化主要是配置AccountId/SecretKey等信息及功能开关。示例代码如下:
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" // 可选,用于鉴权解析
config.EnableHTTPS = true // 是否使用HTTPS
client, err := httpdns.NewClient(config)
if err != nil {
log.Fatal(err)
}
defer client.Close()
}EnableHTTPS参数设置为true后,计费会增加,请仔细阅读产品计费文档。
3.1.1 日志配置
应用开发过程中,如果要输出HTTPDNS的日志,可以在初始化时配置Logger,示例代码如下:
config := httpdns.DefaultConfig()
config.Logger = log.New(os.Stdout, "[HTTPDNS] ", log.LstdFlags)3.2 域名解析
3.2.1 同步解析
同步解析方法会优先返回缓存结果,缓存未命中时发起HTTP请求,示例代码如下:
func resolve(client httpdns.Client) {
ctx := context.Background()
result, err := client.Resolve(ctx, "www.aliyun.com")
if err != nil {
log.Printf("解析失败: %v", err)
return
}
log.Printf("域名: %s", result.Domain)
log.Printf("IPv4: %v", result.IPv4)
log.Printf("IPv6: %v", result.IPv6)
log.Printf("TTL: %v", result.TTL)
}3.2.2 异步解析
当需要非阻塞解析时,可以使用异步解析方法,该方法通过回调返回结果,示例代码如下:
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("异步解析失败: %v", err)
return
}
log.Printf("异步解析结果: %s -> %v", result.Domain, result.IPv4)
})
}3.2.3 批量解析
当需要同时解析多个域名时,可以使用批量解析方法,示例代码如下:
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("批量解析失败: %v", err)
return
}
for _, result := range results {
log.Printf("域名: %s, IPv4: %v", result.Domain, result.IPv4)
}
}单次批量解析最多支持5个域名,超过限制将返回错误。
四、Go最佳实践
通过自定义DialContext,可以将HTTPDNS解析结果无缝集成到标准net/http客户端中,同时支持HTTP和HTTPS。
步骤1:创建HTTPDNS客户端
package main
import (
"context"
"fmt"
"log"
"net"
"net/http"
"os"
"time"
"github.com/aliyun/alicloud-httpdns-go-sdk/pkg/httpdns"
)
func main() {
// 创建HTTPDNS客户端
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()
// 创建集成HTTPDNS的HTTP客户端
httpClient := createHTTPDNSClient(dnsClient)
// 发起请求
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)
}步骤2:创建自定义HTTP客户端
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) {
// 解析域名和端口
host, port, err := net.SplitHostPort(addr)
if err != nil {
return nil, err
}
// 使用HTTPDNS解析域名
result, err := dnsClient.Resolve(ctx, host)
if err != nil {
log.Printf("[DNS Lookup] HTTPDNS解析失败,降级到系统DNS: %s, error: %v", host, err)
return net.Dial(network, addr)
}
// 优先使用IPv4
var resolvedIP string
if len(result.IPv4) > 0 {
resolvedIP = result.IPv4[0].String()
log.Printf("[DNS Lookup] HTTPDNS解析成功: %s -> %s (IPv4)", host, resolvedIP)
} else if len(result.IPv6) > 0 {
resolvedIP = result.IPv6[0].String()
log.Printf("[DNS Lookup] HTTPDNS解析成功: %s -> %s (IPv6)", host, resolvedIP)
} else {
log.Printf("[DNS Lookup] HTTPDNS无可用IP,降级到系统DNS: %s", host)
return net.Dial(network, addr)
}
// 使用解析的IP建立连接
return net.Dial(network, net.JoinHostPort(resolvedIP, port))
},
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
DisableCompression: false,
},
}
}五、API
5.1 初始化
初始化配置,在应用启动时调用。
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()参数:
参数名 | 类型 | 是否必须 | 功能 |
AccountID | string | 必选参数 | Account ID |
SecretKey | string | 可选参数 | 加签密钥 |
BootstrapIPs | []string | 可选参数 | 启动IP列表 |
Timeout | time.Duration | 可选参数 | 解析超时时间,默认5秒 |
MaxRetries | int | 可选参数 | 最大重试次数,默认0 |
EnableHTTPS | bool | 可选参数 | 是否使用HTTPS,默认false |
EnableMetrics | bool | 可选参数 | 是否启用指标统计,默认false |
EnableMemoryCache | bool | 可选参数 | 是否启用内存缓存,默认true |
EnablePersistentCache | bool | 可选参数 | 是否启用持久化缓存,默认false |
AllowExpiredCache | bool | 可选参数 | 是否允许使用过期缓存,默认false |
CacheExpireThreshold | time.Duration | 可选参数 | 持久化缓存过期阈值,默认0 |
Logger | Logger | 可选参数 | 日志记录器 |
5.2 域名解析
解析指定域名。
ctx := context.Background()
result, err := client.Resolve(ctx, "www.aliyun.com")
if err != nil {
log.Printf("解析失败: %v", err)
return
}
fmt.Printf("IPv4: %v\n", result.IPv4)
fmt.Printf("IPv6: %v\n", result.IPv6)参数:
参数名 | 类型 | 是否必须 | 功能 |
ctx | context.Context | 必选参数 | 上下文 |
domain | string | 必选参数 | 域名 |
opts | ...ResolveOption | 可选参数 | 解析选项 |
解析选项:
选项函数 | 功能 |
WithIPv4Only() | 仅解析IPv4 |
WithIPv6Only() | 仅解析IPv6 |
WithBothIP() | 同时解析IPv4和IPv6 |
WithTimeout(duration) | 设置超时时间 |
WithClientIP(ip) | 设置客户端IP,用于就近接入 |
返回字段说明:
字段名 | 类型 | 功能 |
Domain | string | 域名 |
ClientIP | string | 客户端IP |
IPv4 | []net.IP | IPv4地址列表 |
IPv6 | []net.IP | IPv6地址列表 |
TTL | time.Duration | TTL时间 |
Source | ResolveSource | 解析来源 |
Timestamp | time.Time | 解析时间戳 |
5.3 批量解析
批量解析多个域名。
ctx := context.Background()
domains := []string{"www.aliyun.com", "www.taobao.com"}
results, err := client.ResolveBatch(ctx, domains)
if err != nil {
log.Printf("批量解析失败: %v", err)
return
}
for _, result := range results {
fmt.Printf("域名: %s, IPv4: %v\n", result.Domain, result.IPv4)
}参数:
参数名 | 类型 | 是否必须 | 功能 |
ctx | context.Context | 必选参数 | 上下文 |
domains | []string | 必选参数 | 域名列表,最多5个 |
opts | ...ResolveOption | 可选参数 | 解析选项 |
5.4 异步解析
异步解析域名,通过回调返回结果。
ctx := context.Background()
client.ResolveAsync(ctx, "www.aliyun.com", func(result *httpdns.ResolveResult, err error) {
if err != nil {
log.Printf("异步解析失败: %v", err)
return
}
fmt.Printf("解析结果: %v\n", result.IPv4)
})参数:
参数名 | 类型 | 是否必须 | 功能 |
ctx | context.Context | 必选参数 | 上下文 |
domain | string | 必选参数 | 域名 |
callback | func(*ResolveResult, error) | 必选参数 | 回调函数 |
opts | ...ResolveOption | 可选参数 | 解析选项 |
5.5 客户端管理
获取客户端状态和管理客户端生命周期。
// 检查客户端健康状态
isHealthy := client.IsHealthy()
// 获取当前服务IP列表
serviceIPs := client.GetServiceIPs()
// 手动更新服务IP
err := client.UpdateServiceIPs(ctx)
// 获取指标统计
stats := client.GetMetrics()
fmt.Printf("总解析次数: %d\n", stats.TotalResolves)
fmt.Printf("成功率: %.2f%%\n", stats.SuccessRate*100)
fmt.Printf("平均延迟: %v\n", stats.AvgLatency)
// 重置指标统计
client.ResetMetrics()
// 关闭客户端
err := client.Close()六、总结
本文介绍了Go环境下HTTPDNS SDK的使用方法和最佳实践。通过自定义DialContext方式集成HTTP客户端,可以实现高性能、高可用的域名解析服务。主要特点包括:
简单易用:提供同步、异步和批量解析接口
高可用性:内置缓存机制和降级策略
安全可靠:支持鉴权解析和HTTPS通信
通过遵循本文的最佳实践建议,开发者可以在Go应用中高效地集成HTTPDNS服务。