9

我们使用 HTTPClient 来实现 REST API。

我们正在使用以下方式读取服务器响应:

method = new PostMethod(url);
HttpClient client = new HttpClient();
int statusCode = client.executeMethod(method);
String responseBody = method.getResponseBodyAsString();

当我们这样做时,我们会收到以下警告:

Dec 9, 2009 7:41:11 PM org.apache.commons.httpclient.HttpMethodBase getResponseBody
WARNING: Going to buffer response body of large or unknown size. Using getResponseBodyAsStream instead is recommended.

文档继续说:

HttpClient 能够高效地请求/响应正文流。可以提交或接收大型实体而无需在内存中缓冲。如果可以同时执行多个 HTTP 方法,这一点尤其重要。虽然有一些方便的方法可以处理字符串或字节数组等实体,但不鼓励使用它们。除非小心使用,否则它们很容易导致内存不足,因为它们意味着在内存中缓冲完整的实体。

所以我的问题是,如果您确实需要将完整的响应作为字符串(即:存储在数据库中,或使用 DOM 解析),为什么使用流的内存效率更高?

4

4 回答 4

15

使用流比将整个实体作为字符串更有效,因为后者意味着

  1. 在将响应返回到您的代码之前,需要阅读响应的全部内容,并且
  2. 在服务器发送整个响应之前,无法将控制权返回给您的代码。

如果您将响应作为流处理,那么您实际上正在做的是一次处理 N 个字节。这意味着您可以在远程服务器仍在发回下一个数据段时开始处理第一个响应段。因此,如果您的用例允许您在接收到数据时对其进行处理,那么这作为一种访问方法更有意义。

但是,如果您出于某种原因需要将整个响应作为字符串,那么流方法的所有效率对您都没有任何影响 - 因为即使您分段阅读响应,您仍然需要等待整个响应 -并将其全部包含在一个字符串中 - 在您处理它之前。

只有当您有一个可以在获得整个响应正文之前开始处理响应的用例时,才能使用流的效率。

于 2009-12-10T01:00:52.410 回答
4

整个过程的内存效率并不高。如果您从流中读取并将其放入字符串中,您只是将过程分成两部分,这样 HttpClient 类就不会注意到它。

如果你真的需要整个字符串,那么你可以忽略警告。然后由您来确保每个请求不会使用太多内存,这样服务器就不会轻易被 DoS 攻击瘫痪。

于 2009-12-10T00:57:38.613 回答
2

你的问题混淆了这一点。

如果您绝对需要将整个响应作为字符串,请执行此操作,

但是,如果您可以完全摆脱它,请使用流。

当您将整个响应加载到一个字符串中时,整个响应主体同时存在于内存中。

使用流,一次只有一小部分响应保存在内存中。

文档说,尤其是一次有多个大型请求时,将整个请求正文加载到字符串中将需要大量内存。

于 2009-12-10T00:57:56.250 回答
0

如果您要解析为 a org.w3c.Document(或者更好的是 a org.jdom.Document),那么直接使用流真的很容易。前任:

org.apache.http.HttpResponse hr = httpClient.execute(httpRequest);
org.apache.http.HttpEntity he = hr.getEntity();
org.jdom.input.SAXBuilder builder = new SAXBuilder();
org.jdom.Document document = builder.build(he.getContent());
于 2009-12-10T01:07:12.413 回答