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)
疑问
- 未使用异步客户端,为何会出现Future相关报错?
- 如何正确获取响应并使用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
相关产品推荐
相关产品推荐

