如何从HttpClient5响应中获取InputStream?

问题描述 投票:0回答:1

在现有项目中,我有一个 HTTP 服务,它使用 Apache 的 HttpClient 4 获取数据并返回响应

InputStream
,如以下代码示例所示:

public class HttpClient4Demo {
    public static void main(String[] args) throws IOException {
        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            try (Scanner scanner = new Scanner(fetchData(httpClient))) {
                while (scanner.hasNextLine()) {
                    System.out.println(scanner.nextLine());
                }
            }
        }
    }

    private static InputStream fetchData(HttpClient httpClient) throws IOException {
        HttpResponse response = httpClient.execute(new HttpGet(
                "https://dummyjson.com/products/1"
        ));
        return response.getEntity().getContent();
    }
}

我想将该服务迁移到 Apache 的 HttpClient 5,所以我必须重写代码:

public class HttpClient5Demo {
    public static void main(String[] args) throws IOException {
        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            try (Scanner scanner = new Scanner(fetchData(httpClient))) {
                while (scanner.hasNextLine()) {
                    System.out.println(scanner.nextLine());
                }
            }
        }
    }

    private static InputStream fetchData(HttpClient httpClient) throws IOException {
        ClassicHttpResponse response = httpClient.executeOpen(
                null,
                new HttpGet("https://dummyjson.com/products/1"),
                null
        );
        return response.getEntity().getContent();
    }
}

但是该代码给了我一个警告,因为使用

ClassicHttpResponse
时没有使用 try-with-resources。

如果我用 try-with-resources 包裹

ClassicHttpResponse
,我会得到一个关闭的
InputStream
,所以我将无法读取响应数据。

private static InputStream fetchData(HttpClient httpClient) throws IOException {
    try (ClassicHttpResponse response = httpClient.executeOpen(
            null,
            new HttpGet("https://dummyjson.com/products/1"),
            null
    )) {
        return response.getEntity().getContent();
    }
}

我还可以将

response.getEntity()
包装到
ByteArrayInputStream
中,我将得到一个有效的
InputStream
,但这不是一个完美的解决方案,因为整个响应数据将存储在 RAM 中。

private static InputStream fetchData(HttpClient httpClient) throws IOException {
    try (ClassicHttpResponse response = httpClient.executeOpen(
            null,
            new HttpGet("https://dummyjson.com/products/1"),
            null
    )) {
        return new ByteArrayInputStream(EntityUtils.toByteArray(response.getEntity()));
    }
}

那么有什么方法可以在不关闭响应和/或使用 HttpClient 5 将其存储在 RAM 中的情况下获得响应

InputStream

java apache-httpcomponents apache-httpclient-5.x
1个回答
0
投票

简单的方法

要消除警告,请返回

ClassicHttpResponse
而不是
InputStream
,并将其放入 try-with-resources 子句中,如下所示。

public class HttpClient5Demo {
    public static void main(String[] args) throws IOException {
        try (CloseableHttpClient httpClient = HttpClients.createDefault();
             ClassicHttpResponse response = fetchData(httpClient);
             Scanner scanner = new Scanner(response.getEntity().getContent())) {
            while (scanner.hasNextLine()) {
                System.out.println(scanner.nextLine());
            }
        }
    }

    private static ClassicHttpResponse fetchData(HttpClient httpClient) throws IOException {
        return httpClient.executeOpen(null, new HttpGet("https://dummyjson.com/products/1"), null);
    }
}

由于关闭

ClassicHttpResponse
相当于关闭
InputStream
,如果返回后能确保
InputStream
正确关闭,则该警告也可以忽略。

你可能会觉得有点不舒服,所以才来到推荐的方式。

推荐方式

检查HttpClient#executeOpen,这实际上是在调用已弃用的方法HttpClient#execute

强烈建议使用 HttpClientResponseHandler 的执行方法,例如execute(HttpHost, ClassicHttpRequest, HttpClientResponseHandler),以确保客户端自动释放资源。对于特殊情况,仍然可以使用executeOpen(HttpHost, ClassicHttpRequest, HttpContext) 在请求执行后保持响应对象打开。

我们可以参考示例演示了处理HTTP响应的推荐方式,处理过程如下

private static void printData(HttpClient httpClient) throws IOException {
    httpClient.execute(new HttpGet("https://dummyjson.com/products/1"), (response) -> {
        try (Scanner scanner = new Scanner(response.getEntity().getContent())) {
            while (scanner.hasNextLine()) {
                System.out.println(scanner.nextLine());
            }
        }
        return null;
    });
}

return null
这里看起来有点奇怪,但在实际场景中,我们通常将响应映射到另一个对象并返回它。

参考: 迁移到 Apache HttpClient 5.x 经典 API

© www.soinside.com 2019 - 2024. All rights reserved.