繁体   English   中英

如果尝试连接到本地服务 (MinIO),AmazonsS3Client 会抛出 UnknownHostException

[英]AmazonsS3Client throws UnknownHostException if attempting to connect to a local service (MinIO)

简而言之:使用AmazonS3Client连接到MinIO的本地实例会导致抛出UnknownHostException ,因为 url 被解析为http://{bucket_name}.localhost:port


问题详细描述:

我正在为 Java 服务创建集成测试,该服务使用 AmazonS3Client 库从 S3 检索内容。 我在测试容器内使用 MinIO 来执行 Amazon S3 的角色,如下所示:

@Container
static final GenericContainer<?> minioContainer = new GenericContainer<>("minio/minio:latest")
    .withCommand("server /data")
    .withEnv(
        Map.of(
            "MINIO_ACCESS_KEY", AWS_ACCESS_KEY.getValue(),
            "MINIO_SECRET_KEY", AWS_SECRET_KEY.getValue()
        )
    )
    .withExposedPorts(MINIO_PORT)
    .waitingFor(new HttpWaitStrategy()
        .forPath("/minio/health/ready")
        .forPort(MINIO_PORT)
        .withStartupTimeout(Duration.ofSeconds(10)));

然后我使用如下方式动态导出其 url(因为测试容器部署在随机端口):

String.format("http://%s:%s", minioContainer.getHost(), minioContainer.getFirstMappedPort())

这反过来导致 url 像这样:

http://localhost:54123

我在测试运行时遇到的问题在于AmazonS3Client.getObject(String,String)的实际实现 - 在创建请求时它执行以下验证(类S3RequestEndpointResolver ,方法resolveRequestEndpoint ):

...    
if (shouldUseVirtualAddressing(endpoint)) {
        request.setEndpoint(convertToVirtualHostEndpoint(endpoint, bucketName));
        request.setResourcePath(SdkHttpUtils.urlEncode(getHostStyleResourcePath(), true));
    } else {
        request.setEndpoint(endpoint);
        request.setResourcePath(SdkHttpUtils.urlEncode(getPathStyleResourcePath(), true));
    }
}

private boolean shouldUseVirtualAddressing(final URI endpoint) {
    return !isPathStyleAccess && BucketNameUtils.isDNSBucketName(bucketName)
            && !isValidIpV4Address(endpoint.getHost());
}

这反过来为 url http://localhost:54123返回true ,因此该方法

private static URI convertToVirtualHostEndpoint(URI endpoint, String bucketName) {
    try {
        return new URI(String.format("%s://%s.%s", endpoint.getScheme(), bucketName, endpoint.getAuthority()));
    } catch (URISyntaxException e) {
        throw new IllegalArgumentException("Invalid bucket name: " + bucketName, e);
    }
}

将存储桶的名称连接到主机,结果为: http://mybucket.localhost:54123 ,这最终导致抛出UnknownHostException 我可以通过将主机设置为0.0.0.0而不是localhost来解决这个问题,但这几乎不是解决方案。

因此我想知道这是否是AmazonS3Client中的错误/限制? ii) 我是缺少某些东西的人,例如配置不佳?

感谢您的时间

我能够找到解决方案。 查看解析器使用的方法:

private boolean shouldUseVirtualAddressing(final URI endpoint) {
    return !isPathStyleAccess && BucketNameUtils.isDNSBucketName(bucketName)
            && !isValidIpV4Address(endpoint.getHost());
}

返回 true 并将流程引导到错误的连接我发现我们可以在构建客户端时设置第一个变量isPathStyleAccess 在我的例子中,我在我的测试配置中创建了一个 bean 来覆盖主要的:

@Bean
@Primary
public AmazonS3 amazonS3() {

    return AmazonS3Client.builder()
        .withPathStyleAccessEnabled(true) //HERE
        .withCredentials(new AWSStaticCredentialsProvider(
            new BasicAWSCredentials(AWS_ACCESS_KEY.getValue(), AWS_SECRET_KEY.getValue())
        ))
        .withEndpointConfiguration(
            new AwsClientBuilder.EndpointConfiguration(s3Endpoint, region)
        )
        .build();
    
}

对于 SDK V2,解决方案非常相似:

S3AsyncClient s3 = S3AsyncClient.builder()
                .forcePathStyle(true) // adding this one
                .endpointOverride(new URI(s3Endpoint))
                .credentialsProvider(() -> AwsBasicCredentials.create(s3Properties.getAccessKey(), s3Properties.getSecretKey()))
                .build()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM