从Azure Storage SAS URL生成/下载字节流时遇StacklessClosedChannelException
问题场景
使用Java代码从Azure Storage的SAS URL读取Blob并转换为Base64字节流时,抛出io.netty.channel.StacklessClosedChannelException异常,推测为Windows系统下的版本兼容问题。
代码实现
ConnectionProvider connectionProvider = ConnectionProvider.builder("custom-connection-provider") .maxConnections(200) .pendingAcquireMaxCount(5000) .build(); BlobClient blobClient = new BlobClientBuilder() .endpoint(searchMultipleWrapper.getSasUrl().trim()) // 有效的SAS URL .httpClient(new NettyAsyncHttpClientBuilder() .connectionProvider(connectionProvider) .readTimeout(Duration.ofMinutes(10)) .writeTimeout(Duration.ofMinutes(10)) .responseTimeout(Duration.ofMinutes(10)) .build()) .retryOptions(new RequestRetryOptions( RetryPolicyType.EXPONENTIAL, 5, 2, null, null, null )) .buildClient(); log.info("BlobClient Object check {} ", blobClient); // 使用try-with-resources确保InputStream关闭 try (InputStream inputStream = blobClient.openInputStream(); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) { // 将InputStream的数据传输到ByteArrayOutputStream inputStream.transferTo(byteArrayOutputStream); // 转换为Base64 byte[] imageBytes = byteArrayOutputStream.toByteArray(); String base64Image = Base64.getEncoder().encodeToString(imageBytes); log.info("Base 64 : {} ", base64Image); // 打印截断后的Base64字符串(安全起见) log.info("Base64 Image (truncated): " + base64Image.substring(0, Math.min(base64Image.length(), 100)) + "..."); } catch (Exception e) { log.error("Error while processing blob content", e); }
异常信息
stack_trace":"reactor.core.Exceptions$ReactiveException:
io.netty.channel.StacklessClosedChannelException
at reactor.core.Exceptions.propagate(Exceptions.java:410)
at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:102)
at reactor.core.publisher.Mono.block(Mono.java:1779)
at com.azure.storage.blob.specialized.BlobClientBase.openInputStream(BlobClientBase.java:393)
at com.azure.storage.blob.specialized.BlobClientBase.openInputStream(BlobClientBase.java:323)
at com.azure.storage.blob.specialized.BlobClientBase.openInputStream(BlobClientBase.java:312)
at com.azure.storage.blob.specialized.BlobClientBase.openInputStream(BlobClientBase.java:299)
解决方法
该异常由Windows环境下Netty与Azure SDK的兼容问题引发,可通过以下方式处理:
替换HttpClient实现:改用Apache HttpClient替代Netty,修改代码中的HttpClient配置段:
// 替换原Netty客户端配置 .httpClient(HttpClient.createDefault())需确保项目引入
azure-core-http-apache依赖。升级Azure SDK版本:将Azure Storage Blob SDK升级至12.25.0及以上版本,该版本已修复Windows环境下的相关兼容问题。
调整Netty连接参数:若继续使用Netty,可尝试禁用连接保持:
.httpClient(new NettyAsyncHttpClientBuilder() .connectionProvider(connectionProvider) .keepAlive(false) // 添加该配置 .readTimeout(Duration.ofMinutes(10)) .writeTimeout(Duration.ofMinutes(10)) .responseTimeout(Duration.ofMinutes(10)) .build())
内容的提问来源于stack exchange,提问作者Ravindra Kushwaha

