从http获取响应哪种方式更好?为什么?

时间:2013-09-26 11:44:21

标签: java android httpresponse java-io

我想知道从http调用获得响应的两种方式的一般区别。

以下是Android示例,但在Java中它们完全相同。

仅使用org.apache.http库的第一个示例:

String s = "";

try {

    HttpPost httppost = new HttpPost(url);
    HttpClient httpclient = new DefaultHttpClient();
    HttpResponse response = httpclient.execute(httppost);
    HttpEntity entity = response.getEntity();

    s = EntityUtils.toString(entity, HTTP.UTF_8);

    // do something with s      
} catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

使用BufferedReader获取响应的第二个示例:

HttpClient httpclient = new DefaultHttpClient();
HttpGet httpget = new HttpGet(url);
HttpResponse response = httpclient.execute(httpget);
HttpEntity entity = response.getEntity();

InputStream instream = entity.getContent();
BufferedReader bufferedreader = new BufferedReader(new InputStreamReader(
                instream));

try {
    String line;
    StringBuilder sb = new StringBuilder();
    while((line = bufferedreader.readLine()) != null)
            sb.append(line);

        // do something with the stringbuilder

} catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

在哪些场景中,我更喜欢第一个使用Stream和Reader的第二个示例,反之亦然?我提出这个问题有一些重要的想法。如果没有包含重点,请告诉我:

  1. 阅读器方法占用更多空间和时间。
  2. 响应数据的大小对第一个或第二个示例没有影响。
  3. 第二个示例中的代码更复杂(有更多开销)。
  4. 由于图书馆中不同的读者数量,读者的方法更灵活。
  5. 这一点让我赞成第一个例子。

2 个答案:

答案 0 :(得分:3)

两个版本的性能差异可能不会对您的应用程序的整体性能产生重大影响。 (如果响应主体非常大,可能可能很重要,但即使这样,性能也可能受网络延迟和带宽考虑因素的影响。)

假设性能差异不太可能显着,另一个需要考虑的是代码的可维护性;即,阅读和修改是多么容易。我的感觉是第一个版本更简单,因此更容易正确,更容易维护。


  

1)Reader方法占用了更多的空间和时间。

不一定。差异(如果有的话)将是在创建结果字符串之前累积数据的方式。如果HTTP响应包含Content-length标头,那么可能第一个版本可以预先分配正确大小的byte[]。相比之下,第二个版本在StringBuilder中累积数据,这可能需要多次重新分配/复制构建器的后备阵列。 (额外的工作是O(N)因此它不会改变计算复杂性的整体衡量标准。但它仍会影响性能......和内存使用。)

  

2)响应数据的大小对第一个或第二个例子没有影响。

不正确的。它在两种情况下都有影响。 (显然......长时间的回复需要更长的时间来阅读而不是短回应......在这两种情况下都是如此!!)

  

3)第二个例子中的代码更复杂(有更多的开销)。

它更复杂,但这并不意味着有更多的开销。在第一种情况下,也存在复杂性,但必须编写代码。但无论如何,简单并不一定意味着更高的效率/更低的开销。这不是性能如何运作......

  

4)由于图书馆中不同的读者数量,读者方法更加灵活。

无关。在这种情况下,您已经很好地选择了Reader类。灵活性在这里没有任何区别。


还有其他问题:

  • 两个版本都假定响应正文是文本。
  • 第一个版本假定响应正文以UTF-8编码。
  • 第二个版本假设响应正文使用(本地)平台的默认编码进行编码。
  • 第二个版本吞噬了换行符。那是一个错误。

错误说明:readLine()方法读取一行并在没有行分隔符的情况下返回它。然后,您的代码会将其添加到StringBuilder ...而不添加行分隔符。最终结果是StringBuilder包含删除了所有行分隔符的数据。哎呀!

答案 1 :(得分:2)

第一个示例使用Apache EntityUtils来读取String中的流。从代码中,它的作用是使用Readerchar[]中读取固定大小entity.getContent()的内容,并将其附加到缓冲区的形式。

第二个示例使用BufferedReader逐行读取。

  1. BufferedReader本身可能不会占用更多空间,但缓冲化所需的空间量是未知的,因为它需要读取一条线(即直到找到换行符),并且可能不是响应中的任何换行符。整个行被缓冲,然后读取到一个字符串,然后追加,使其在内存中出现3次。

  2. 商定

  3. BufferedReader示例的代码显然更长。

  4. 任何不使用第三方方法的方法都更灵活,因为您可以处理流的内容而无需等待阅读整个内容

  5. readLine方法有另一个缺陷,即丢失换行符。在某些情况下,他们可能会携带信息。

  6. 如果您想要一种高效而灵活的方法,请查看apache EntityUtils的实际实现。它使用固定大小的char []进行缓冲,确保您知道内存开销量,并读取所有字符,包括换行符。

    只有当你需要阅读一行时,

    readLine才真正有用。 (!)

    (实施的相关部分:)

        Reader reader = new InputStreamReader(instream, charset);
        CharArrayBuffer buffer = new CharArrayBuffer(i);
        try {
            char[] tmp = new char[1024];
            int l;
            while((l = reader.read(tmp)) != -1) {
                buffer.append(tmp, 0, l);
            }
        } finally {
            reader.close();
        }