【问题标题】:AmazonsS3Client throws UnknownHostException if attempting to connect to a local service (MinIO)如果尝试连接到本地服务 (MinIO),AmazonsS3Client 会抛出 UnknownHostException
【发布时间】:2022-11-21 05:56:37
【问题描述】:

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


问题详细描述:

我正在为使用 AmazonS3Client 库从 S3 检索内容的 Java 服务创建集成测试。我在测试容器内使用 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())

这反过来会导致这样的网址:

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)我是那个缺少东西的人,例如配置差?

感谢您的时间

【问题讨论】:

    标签: java amazon-s3 minio testcontainers


    【解决方案1】:

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

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

    它返回 true 并导致流向错误的连接我发现我们可以在构建客户端时设置第一个变量isPathStyleAccess。在我的例子中,我在我的测试配置中创建了一个 bean 来覆盖主要的 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();
        
    }
    

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

        猜你喜欢
        • 2021-11-12
        • 2022-12-18
        • 2018-09-22
        • 1970-01-01
        • 2019-10-15
        • 1970-01-01
        • 2021-04-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多