You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

S3EncryptionClient同步调用遇headersFuture未完成异常求助

问题

我们正在迁移至aws-sdk和amazon-s3-encryption-client-java的最新版本(2.24.5),当前使用3.1.1版本的S3EncryptionClient代码,在读取S3对象时触发异常。

代码实现

private S3EncryptionClient getEncryptionClient(String regionName, KeyPair keyPair) {
    return S3EncryptionClient.builder()
            .rsaKeyPair(keyPair)
            .enableDelayedAuthenticationMode(true)
            .enableLegacyUnauthenticatedModes(true)
            .enableLegacyWrappingAlgorithms(true)
            .wrappedClient(getClient(regionName))
            .wrappedAsyncClient(getAsyncClient(regionName))
            .build();
}

private ClientOverrideConfiguration createClientConfiguration() {
    return S3Client.builder()
            .httpClient(
                    ApacheHttpClient.builder()
                            .connectionTimeout(Duration.ofMillis(clientConnectionTimeout))
                            .build())
            .overrideConfiguration()
            .toBuilder()
            .retryPolicy(RetryPolicy.builder().numRetries(NUM_RETRIES).build())
            .apiCallAttemptTimeout(Duration.ofMillis(clientRequestTimeout))
            .build();
}

// 调用代码
s3Client.getObject(getGetObjectRequest(storageKey)), isZip;

异常信息

Caused by: software.amazon.encryption.s3.S3EncryptionClientException: Unable to execute HTTP request: headersFuture is still not completed when onStream() is invoked.
    at deployment.fs.war//software.amazon.encryption.s3.S3EncryptionClient.getObject(S3EncryptionClient.java:255)
    
Caused by: software.amazon.awssdk.core.exception.SdkClientException: Unable to execute HTTP request: headersFuture is still not completed when onStream() is invoked.
    at deployment.fs.war//software.amazon.awssdk.core.exception.SdkClientException$BuilderImpl.build(SdkClientException.java:111)
    at deployment.fs.war//software.amazon.awssdk.core.exception.SdkClientException.create(SdkClientException.java:47)
    at deployment.fs.war//software.amazon.awssdk.core.internal.http.pipeline.stages.utils.RetryableStageHelper.setLastException(RetryableStageHelper.java:223)
    at deployment.fs.war//software.amazon.awssdk.core.internal.http.pipeline.stages.utils.RetryableStageHelper.setLastException(RetryableStageHelper.java:218)
    at deployment.fs.war//software.amazon.awssdk.core.internal.http.pipeline.stages.AsyncRetryableStage$RetryingExecutor.maybeRetryExecute(AsyncRetryableStage.java:182)
    at deployment.fs.war//software.amazon.awssdk.core.internal.http.pipeline.stages.AsyncRetryableStage$RetryingExecutor.lambda$attemptExecute$1(AsyncRetryableStage.java:159)
    at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:859)

疑问

  1. 未使用异步客户端,为何会出现Future相关报错?
  2. 如何正确获取响应并使用InputStream?未找到可等待的wait/join方法。

解决方案

对疑问1的解释

你虽然在业务代码里调用的是同步getObject方法,但构建S3EncryptionClient时同时传入了同步客户端和异步客户端。新版加密客户端内部会根据配置自动选择执行路径,当两种客户端同时存在时,会优先触发异步执行逻辑,导致内部出现Future相关的异步处理流程,进而抛出该异常。另外,这种混合配置同步/异步客户端的方式,在新版SDK中属于不规范用法,也是触发问题的核心原因。

对疑问2的解决方法

修正客户端构建逻辑,仅传入同步客户端,同时规范getObject的调用方式:

修正后的客户端构建代码

private S3EncryptionClient getEncryptionClient(String regionName, KeyPair keyPair) {
    return S3EncryptionClient.builder()
            .rsaKeyPair(keyPair)
            .enableDelayedAuthenticationMode(true)
            .enableLegacyUnauthenticatedModes(true)
            .enableLegacyWrappingAlgorithms(true)
            // 仅保留同步客户端配置,移除异步客户端
            .wrappedClient(getClient(regionName))
            .build();
}

// 确保同步S3Client的配置完整
private S3Client getClient(String regionName) {
    return S3Client.builder()
            .region(Region.of(regionName))
            .httpClient(ApacheHttpClient.builder()
                    .connectionTimeout(Duration.ofMillis(clientConnectionTimeout))
                    .build())
            .overrideConfiguration(createClientConfiguration())
            .build();
}

正确读取对象的代码

// 使用try-with-resources自动管理资源,同步API会阻塞至响应就绪
try (GetObjectResponse response = s3Client.getObject(getGetObjectRequest(storageKey));
     InputStream inputStream = response.body()) {
    // 处理输入流逻辑
    if (isZip) {
        try (ZipInputStream zipInputStream = new ZipInputStream(inputStream)) {
            ZipEntry entry;
            while ((entry = zipInputStream.getNextEntry()) != null) {
                // 处理单个压缩条目
            }
        }
    } else {
        // 处理普通输入流
    }
}

关键注意点

  • 新版S3EncryptionClient建议仅配置所需的客户端类型(同步或异步),避免混合配置导致内部逻辑冲突。
  • 同步API的getObject本身就是阻塞式调用,无需额外使用wait/join方法,响应就绪后才会返回结果。用try-with-resources语法可以自动关闭响应和输入流,避免资源泄漏。

内容的提问来源于stack exchange,提问作者Eugene Kisly

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 06:27:15