Java端HTTPDNS+阿里云OSS SDK最佳实践

更新时间:
复制为 MD 格式

通过Java SDK接入指南这篇文档,您已经了解了Java SDK导入、配置、解析IP、应用到网络库和接入验证的完整流程,本文主要介绍在Java客户端上使用阿里云OSS SDK接入HTTPDNS的具体方案。

1. 背景说明

阿里云对象存储OSS(Object Storage Service)是一款通用的云存储服务,可让开发者在各类应用中便捷地存储和访问用户头像、图片、音视频等文件。在Java端,可以通过集成OSS Java SDK来完成。

为了提升文件传输的稳定性和速度,可以将HTTPDNS SDKOSS Java SDK进行结合,对OSS域名进行解析。这可以有效实现域名防劫持和DNS解析加速,从而优化应用访问OSS的网络体验。

2. 环境要求

  • Java 8 或以上

  • OSS Java SDK V2 (alibabacloud-oss-v2) 0.1.0-beta1 或以上

  • HTTPDNS Java SDK (alicloud-java-httpdns) 1.0.0 或以上

3. 基于 Apache HttpClient 实现 DnsResolver

OSS Java SDK V2 底层使用 Apache HttpClient,支持 4.x 和 5.x 两个版本。通过实现 DnsResolver 接口,可以将 HTTPDNS 集成到 OSS SDK 中。

HttpClient 5.x(默认)

import org.apache.hc.client5.http.DnsResolver;
import com.alibaba.sdk.java.httpdns.HttpDnsClient;
import com.alibaba.sdk.java.httpdns.HTTPDNSResult;
import com.alibaba.sdk.java.httpdns.RequestIpType;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;

public class HttpDnsResolver implements DnsResolver {

    @Override
    public String resolveCanonicalHostname(String host) { return host; }

    @Override
    public InetAddress[] resolve(String host) throws UnknownHostException {
        HTTPDNSResult result = HttpDnsClient.getClient("your-account-id")
                .getHttpDnsResultForHostSyncNonBlocking(host, RequestIpType.both);

        List<InetAddress> addresses = new ArrayList<>();
        addAddresses(addresses, result != null ? result.getIps() : null);
        addAddresses(addresses, result != null ? result.getIpv6s() : null);
        
        return addresses.isEmpty() ? InetAddress.getAllByName(host) : addresses.toArray(new InetAddress[0]);
    }

    private void addAddresses(List<InetAddress> list, String[] ips) {
        if (ips == null) return;
        for (String ip : ips) {
            try { list.add(InetAddress.getByName(ip)); } catch (UnknownHostException e) {}
        }
    }
}

HttpClient 4.x

import org.apache.http.conn.DnsResolver;
import com.alibaba.sdk.java.httpdns.HttpDnsClient;
import com.alibaba.sdk.java.httpdns.HTTPDNSResult;
import com.alibaba.sdk.java.httpdns.RequestIpType;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;

public class HttpDnsResolver4 implements DnsResolver {

    @Override
    public InetAddress[] resolve(String host) throws UnknownHostException {
        HTTPDNSResult result = HttpDnsClient.getClient("your-account-id")
                .getHttpDnsResultForHostSyncNonBlocking(host, RequestIpType.both);

        List<InetAddress> addresses = new ArrayList<>();
        addAddresses(addresses, result != null ? result.getIps() : null);
        addAddresses(addresses, result != null ? result.getIpv6s() : null);
        
        return addresses.isEmpty() ? InetAddress.getAllByName(host) : addresses.toArray(new InetAddress[0]);
    }

    private void addAddresses(List<InetAddress> list, String[] ips) {
        if (ips == null) return;
        for (String ip : ips) {
            try { list.add(InetAddress.getByName(ip)); } catch (UnknownHostException e) {}
        }
    }
}
说明

4.x 和 5.x 的 DnsResolver 来自不同的包,5.x 需额外实现 resolveCanonicalHostname() 方法。

4. 接入OSS SDK

创建自定义 HttpClient 实例,并配置到 OSSClient 以替代默认 DNS 服务。

HttpClient 5.x(默认)

import com.alibaba.sdk.java.httpdns.HttpDnsClient;
import com.alibaba.sdk.java.httpdns.InitConfig;
import com.aliyun.sdk.service.oss2.OSSClient;
import com.aliyun.sdk.service.oss2.credentials.EnvironmentVariableCredentialsProvider;
import com.aliyun.sdk.service.oss2.transport.apache5client.Apache5HttpClient;
import com.aliyun.sdk.service.oss2.transport.apache5client.Apache5HttpClientBuilder;

// 初始化 HTTPDNS
InitConfig config = new InitConfig.Builder()
        .setSecretKey("your-secret-key")
        .setEnableHttps(true)
        .setTimeoutMillis(2000)
        .setEnableExpiredIp(true)
        .enableMemoryCache(true)
        .build();
HttpDnsClient.init("your-account-id", config);

// 创建 HttpClient 并注入 DnsResolver
Apache5HttpClient httpClient = Apache5HttpClientBuilder.create()
        // ... 其他 HttpClient 配置
        .dnsResolver(new HttpDnsResolver())
        .build();

// 创建 OSSClient
OSSClient ossClient = OSSClient.newBuilder()
        // ... 其他 OSS 配置
        .httpClient(httpClient)
        .build();

HttpClient 4.x

// 初始化 HTTPDNS
InitConfig config = new InitConfig.Builder()
        .setSecretKey("your-secret-key")
        .setEnableHttps(true)
        .setTimeoutMillis(2000)
        .setEnableExpiredIp(true)
        .enableMemoryCache(true)
        .build();
HttpDnsClient.init("your-account-id", config);

// 创建 HttpClient 并注入 DnsResolver
Apache4HttpClient httpClient = Apache4HttpClientBuilder.create()
        // ... 其他 HttpClient 配置
        .dnsResolver(new HttpDnsResolver4())
        .build();

// 创建 OSSClient 时注入 httpClient
OSSClient ossClient = OSSClient.newBuilder()
        // ... 其他 OSS 配置
        .useApacheHttpClient4(true)  // 指定使用 HttpClient 4.x
        .httpClient(httpClient)
        .build();
重要

HTTPDNS SDK初始化设置需要在OSS SDK初始化设置之前完成。

5. 总结

通过将 HTTPDNS 与 OSS SDK 结合,可以有效防止 DNS 劫持并加速域名解析,提升访问的稳定性和安全性。实现的核心是为 OSS 配置一个带有 HTTPDNS 解析逻辑的自定义 HttpClient。

关键注意点:

  • 自定义 HttpClient 后,需将超时、并发数等配置手动设置到 HttpClientBuilder 上,否则原配置会失效

  • 需要先初始化 HTTPDNS,再初始化 OSS。并确保 OSS 域名已添加到 HTTPDNS 控制台的域名白名单中