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

Apache HttpClient获取Azure Blob时出现ConnectionClosedException求助

Apache HttpClient获取Azure Blob内容时抛出ConnectionClosedException异常

使用Apache HttpClient获取HTTP响应,已成功获取响应头,但读取响应内容时抛出ConnectionClosedException,异常提示内容长度不匹配(预期42320字节,实际仅收到7787字节)。

异常栈信息

Caused by: org.apache.http.ConnectionClosedException: Premature end of Content-Length delimited message body (expected: 42 320; received: 7 787)
[INFO] [talledLocalContainer]   at org.apache.http.impl.io.ContentLengthInputStream.read(ContentLengthInputStream.java:178) ~[httpcore-4.4.15.jar:4.4.15]
[INFO] [talledLocalContainer]   at org.apache.http.conn.EofSensorInputStream.read(EofSensorInputStream.java:135) ~[httpclient-4.5.13.jar:4.5.13]
[INFO] [talledLocalContainer]   at org.apache.http.conn.EofSensorInputStream.read(EofSensorInputStream.java:148) ~[httpclient-4.5.13.jar:4.5.13]
[INFO] [talledLocalContainer]   at com.blueway.common.utils.BWFileUtils.writeToFile(BWFileUtils.java:207) ~[engine-module-common-0.0.1-SNAPSHOT.jar:?]
[INFO] [talledLocalContainer]   at com.blueway.platform.app.engine.technicalconnector.impl.service.azureblobstorage.AzureBlobStorageService.getBlob(AzureBlobStorageService.java:49) ~[web-0.0.1-SNAPSHOT.jar:?]
[INFO] [talledLocalContainer]   at com.blueway.platform.app.engine.technicalconnector.impl.service.azureblobstorage.invoker.AzureBlobStorageGetBlobInvoker.invoke(AzureBlobStorageGetBlobInvoker.java:22) ~[web-0.0.1-SNAPSHOT.jar:?]
[INFO] [talledLocalContainer]   at com.blueway.platform.app.engine.technicalconnector.impl.service.azureblobstorage.AzureBlobStorageInvokeWrapper.doInvoke(AzureBlobStorageInvokeWrapper.java:34) ~[web-0.0.1-SNAPSHOT.jar:?]
[INFO] [talledLocalContainer]   at com.blueway.engine52.support.ConnectorAzureBlobStorage.invoke(ConnectorAzureBlobStorage.java:46) ~[web-0.0.1-SNAPSHOT.jar:?]
[INFO] [talledLocalContainer]   at com.blueway.engine52.service.instruction.ConnectorHandlingInstruction.invokeConnector(ConnectorHandlingInstruction.java:68) ~[web-0.0.1-SNAPSHOT.jar:?]
[INFO] [talledLocalContainer]   at com.blueway.engine52.service.instruction.ConnectorHandlingInstruction.executeInstructionWithSupport(ConnectorHandlingInstruction.java:50) ~[web-0.0.1-SNAPSHOT.jar:?]
[INFO] [talledLocalContainer]   at com.blueway.engine52.service.instruction.ConnectorHandlingInstruction.executeInstructionWithSupport(ConnectorHandlingInstruction.java:19) ~[web-0.0.1-SNAPSHOT.jar:?]
[INFO] [talledLocalContainer]   at com.blueway.engine52.service.instruction.SupportHandlingInstruction.executeInstruction(SupportHandlingInstruction.java:99) ~[web-0.0.1-SNAPSHOT.jar:?]
[INFO] [talledLocalContainer]   at com.blueway.engine52.service.instruction.Instruction.tryExecuteInstruction(Instruction.java:363) ~[web-0.0.1-SNAPSHOT.jar:?]

问题代码

public CloseableHttpResponse get(final String containerName, final String blobName) throws AzBException{
    final Logger logger = LoggerFactory.getLogger(getClass());

    final String url = HTTPS + accountName + END_POINT + containerName + "/" + blobName;
    try (final CloseableHttpClient httpClient = HttpClients.createDefault()) {
        final HttpGet httpGet = new HttpGet(url);
        logger.debug("Sending HTTP GET request to URL: {}", url);
        final CloseableHttpResponse  response = httpClient.execute(httpGet);
        logger.debug("Received HTTP response with status code: {}", response.getStatusLine().getStatusCode());
        return response;
    } catch (IOException e) {
        throw new AzBException("An.get HttpGet error: " + e.getCause().getMessage(), e);
    }
}

解决方案

问题根源

代码使用try-with-resources创建CloseableHttpClient,当方法返回CloseableHttpResponse时,HttpClient已经被自动关闭,导致后续读取响应流时连接提前断开,无法获取完整的响应内容。

修复方案1:复用HttpClient(推荐)

HttpClient是线程安全的,建议将其作为类级别的成员变量全局复用,避免每次请求都创建和关闭客户端:

private final CloseableHttpClient httpClient = HttpClients.createDefault();
private final Logger logger = LoggerFactory.getLogger(getClass());

public CloseableHttpResponse get(final String containerName, final String blobName) throws AzBException{
    final String url = HTTPS + accountName + END_POINT + containerName + "/" + blobName;
    try {
        final HttpGet httpGet = new HttpGet(url);
        logger.debug("Sending HTTP GET request to URL: {}", url);
        final CloseableHttpResponse response = httpClient.execute(httpGet);
        logger.debug("Received HTTP response with status code: {}", response.getStatusLine().getStatusCode());
        return response;
    } catch (IOException e) {
        throw new AzBException("An.get HttpGet error: " + e.getMessage(), e);
    }
}

// 应用关闭时手动释放HttpClient资源
@PreDestroy
public void closeHttpClient() throws IOException {
    httpClient.close();
}

修复方案2:在方法内完成响应内容读取

如果不需要返回响应对象,可以在方法内部直接读取响应内容,使用try-with-resources同时管理HttpClient和响应对象,确保资源正确释放:

public byte[] get(final String containerName, final String blobName) throws AzBException{
    final Logger logger = LoggerFactory.getLogger(getClass());
    final String url = HTTPS + accountName + END_POINT + containerName + "/" + blobName;
    try (final CloseableHttpClient httpClient = HttpClients.createDefault();
         final CloseableHttpResponse response = httpClient.execute(new HttpGet(url))) {
        logger.debug("Received HTTP response with status code: {}", response.getStatusLine().getStatusCode());
        // 读取响应内容为字节数组,EntityUtils会自动处理流关闭
        return EntityUtils.toByteArray(response.getEntity());
    } catch (IOException e) {
        throw new AzBException("An.get HttpGet error: " + e.getMessage(), e);
    }
}

如果需要将内容写入文件,可直接在try块内完成写入操作,避免传递未处理的响应流:

public void getBlobToFile(final String containerName, final String blobName, File targetFile) throws AzBException{
    final Logger logger = LoggerFactory.getLogger(getClass());
    final String url = HTTPS + accountName + END_POINT + containerName + "/" + blobName;
    try (final CloseableHttpClient httpClient = HttpClients.createDefault();
         final CloseableHttpResponse response = httpClient.execute(new HttpGet(url));
         final InputStream inputStream = response.getEntity().getContent()) {
        logger.debug("Received HTTP response with status code: {}", response.getStatusLine().getStatusCode());
        // 直接写入文件
        BWFileUtils.writeToFile(inputStream, targetFile);
    } catch (IOException e) {
        throw new AzBException("Failed to get blob to file: " + e.getMessage(), e);
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 03:34:52