替代Apache HttpComponents的选择?

49

所以,我得出结论,Apache HttpComponents 4 是我见过的最复杂的 API 之一。一些看似简单的事情需要数百行代码(而且我甚至还不确定资源是否被正确清理)。

此外,它让我做像这样的事情:

List<NameValuePair> qparams = new ArrayList<NameValuePair>();
qparams.add(new BasicNameValuePair("q", "httpclient"));
qparams.add(new BasicNameValuePair("btnG", "Google Search"));
qparams.add(new BasicNameValuePair("aq", "f"));
qparams.add(new BasicNameValuePair("oq", null));
URI uri = URIUtils.createURI("http", "www.google.com", -1, "/search", 
  URLEncodedUtils.format(qparams, "UTF-8"), null);

这个Java库有点过于冗长了,而且它的jar文件大小高达700KB。不过别管那么多,我想知道大家使用其他HTTP客户端库的经验如何?

我知道的一些库有:JettyhotpotatoAsyncHttpClient

我主要是想在服务器端执行许多并发获取和大文件传输时获得更好的性能。你们有什么推荐吗?

附注:我知道旧版本的HttpClient 3.1仍然存在,但我想使用受支持的库。

更新

@oleg:这是文档建议的内容:

    HttpClient httpclient = new DefaultHttpClient();
    try {
        HttpGet httpget = new HttpGet("http://www.apache.org/");
        HttpResponse response = httpclient.execute(httpget);
        HttpEntity entity = response.getEntity();
        if (entity != null) {
            InputStream instream = entity.getContent();
            try {
                instream.read();
            } catch (IOException ex) {
                throw ex;
            } catch (RuntimeException ex) {
                httpget.abort();
                throw ex;
            } finally {
                try { instream.close(); } catch (Exception ignore) {}
            }
        }
    } finally {
        httpclient.getConnectionManager().shutdown();
    }

使用 ThreadSafeClientConnManager 时,当尝试消费实体内容时,我仍然会遇到意外错误。我确定这是我的问题,但此时我真的不想再去解决它。

嘿,我并不是要贬低任何人的工作,但我已经在努力使用 HttpComponents 自从4.0发布以来,但它对我来说根本不起作用。


1
虽然不是完美的,但你有考虑过标准的URLConnection/HTTPUrlConnection吗? - nos
4
需要调用InputStream#close()来释放分配的资源,这难道不是非常复杂吗? - ok2c
3
自 4.0 版本以来,每个点发布的 API 都已经更改了多次,比我换内裤的次数还要多。 - RTF
2
@RTF 我不认识你,所以我无法判断API是否变化快,或者我是否应该避免你家的气味:D - Joffrey
1
@Joffrey 有点儿A列,也有点儿B列 - RTF
显示剩余2条评论
9个回答

21

HttpClient API的复杂性反映了它所解决问题领域的复杂性。与一种常见误解相反,HTTP是一种相当复杂的协议。作为低级别传输库,HC 4.0 API主要针对性能和灵活性进行优化,而不是简单性。很遗憾你无法理解,但没关系。您可以使用最适合您需求的任何库。我个人非常喜欢Jetty HttpClient,它是一个很好的替代方案,可能更适合您。


4
我同意你和原帖作者的观点。强大和灵活的功能是必要的,但同时也应该有一组外观方法来简化流程。例如像 public static InputStream httpGetAsStream(String baseUrl, Map<String, Object> parameters) 这样的方法。 - Sean Patrick Floyd
21
HTTP协议很复杂,但Apache的HttpComponents库过于工程化,包含了很多与协议操作无关的复杂性。它的API确实非常糟糕。 - Alex B
3
@Alex B:HttpComponents被应用于各种不同的应用程序,从简单的URL获取器到具有不同、常常相互冲突需求的复杂传输和网络爬虫。对某些人来说似乎不重要的东西对其他人可能非常重要。HttpClient必须处理几十个自定义参数以及上下文特定的策略和对象。因此,灵活性必须放在简单性之前。对于那些无法理解HttpClient API的人,可以使用流畅的Facade API:http://hc.apache.org/httpcomponents-client-dev/fluent-hc/index.html - ok2c
5
HttpClient API 的复杂性反映出其问题领域本身就很复杂。如果 HC 4.0 完美无缺,那么这将是一个优点,但实际上并不是这样。它存在许多问题,我想缺乏指导可能导致了现在的混乱局面。我认为 Alex B 是正确的,当他说客观地看,该 API 很糟糕,本应该做得更好。本可以更好。 - Zombies
2
@SeanPatrickFloyd 应该有一组外观方法 确实存在这样一组方法:Apache HttpComponents Fluent API。(如上面的评论中oleg所指出的) - Basil Bourque
@oleg 我正在转换到Jetty HttpClient,到目前为止我非常喜欢它,但是我无法在Fiddler中捕获HTTPS流量。我尝试了很多方法,但是当我将HTTPS流量代理到Fiddler时仍然会出现异常。这对我来说非常重要,因为我需要它进行调试。我没有问题捕获Apache HttpClient或URLConnection的流量。你或这里的任何人知道我需要做什么吗? - Arya

16

对于简单应用场景,您可以使用HttpClient流畅API。请参见教程

该模块提供了一个易于使用的外观API,基于流畅接口的概念,用于HttpClient。流畅外观API仅公开HttpClient的最基本功能,并且适用于不需要完全灵活性的简单用例。例如,流畅外观API使用户摆脱了处理连接管理和资源释放的烦恼。

    // Execute a GET with timeout settings and return response content as String.
 Request.Get("http://somehost/")
        .connectTimeout(1000)
        .socketTimeout(1000)
        .execute().returnContent().asString();

Maven构件。

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>fluent-hc</artifactId>
    <version>4.2.5</version>
</dependency>

3
更新:现在有很多更好的替代品。OkHttp和Retrofit 是非常棒的库,对于大多数现代应用程序来说它们既简洁又完美地实现了功能。 - forresthopkinsa

6
回答自己的问题,因为某些原因这个问题被重新提出。我最终编写了几个简单的包装器来包装 java.net.HttpURLConnection,看起来它已经发展了很长一段时间,自上次我认真考虑它以来。 Apache HttpComponents 很棒,但对于简单任务可能过于复杂。此外,在我的情况下,HUC 明显更快(主要是单线程,没有在重负载下进行任何测试)。

2
HttpURLConnection实例的创建成本要比HttpClient便宜得多,因为它们共享一个静态的JRE连接池。默认情况下,HttpClient总是创建一个新的连接池,因此启动和预热速度较慢。可以通过重用HttpClient的相同实例来解决这个问题以处理新请求。HttpClient的流畅外观就采用了这种方法:http://hc.apache.org/httpcomponents-client-dev/fluent-hc/index.html。在我所能想到的所有其他情况中,HttpClient应该更快。 - ok2c
2
也许我做错了什么,这不是十分严格的基准测试。我总是使用单个HttpClient实例。只是进行了一个快速测试:从本地主机获取一个非常小的文档(150字节)x 5000次,使用HttpClient(4.1)大约需要10秒钟,而使用HUC则不到2秒钟。实际上,这不仅是学术上的问题,我的主要用例是针对同一台机器上的服务进行大量的小查找。 - Dmitri
2
我只能给你我的(有偏见的)观点。任何持续2秒的HTTP性能测试都不具有代表性。需要运行基准测试几分钟才能获得更可靠的数字。这是我们内部使用的基准测试和一些结果:http://wiki.apache.org/HttpComponents/HttpClient3vsHttpClient4vsHttpCore。与HUC和其他客户端相比,HttpClient 4.x的性能似乎相当不错。 - ok2c
2
当然。就像我说的,这并不是一个全面的基准测试。然而,在我的特定情况下,你的基准测试没有涵盖到,有明显的差异。我不会从那个例子中得出一般性结论(肯定不具代表性),但它确实影响了我在我的场景中使用什么的决策。 - Dmitri

4

jsoup

Jsoup是一个解析HTML文件的库。它会进行HTTP调用以获取网页源代码。

Document doc = Jsoup.connect("http://en.wikipedia.org/").get();

4

Google HTTP客户端

另一个库是Google HTTP客户端Java库

这个库由谷歌编写,是一种灵活、高效、强大的Java客户端库,可通过HTTP访问Web上的任何资源。它具有可插拔的HTTP传输抽象,允许使用任何低级库,例如java.net.HttpURLConnection、Apache HTTP Client或在Google应用引擎上使用的URL Fetch。它还具有高效的JSON和XML数据模型,用于解析和序列化HTTP响应和请求内容。JSON和XML库也是完全可插拔的,包括支持Jackson和Android的GSON库用于JSON。


3
我是JAX-RS(2.0标准化)的客户端API的粉丝,特别是Jersey的实现。它支持异步,并具有连接器,因此可以由Apache HttpComponents、普通HttpUrlConnection、Jetty或Grizzly支持。
这里有一些很好的使用示例在这里,包括以下内容。
client.target(REST_SERVICE_URL)
      .path("/{bookId}")
      .resolveTemplate("bookId", bookId)
      .request()
      .get(Book.class);

3
你可以使用 Netty 或者 Apache Mina,虽然它们都是非常底层的,我不确定你是否能够写出更简洁的代码。

1
你可以看一下Restlet的客户端功能。它是一个在上层的层次,可以被Apache HttpComponents或Java的Net API所支持。

1
我使用了Jersey的客户端,概念上非常相似。它在许多情况下非常方便。 - Dmitri

1

HTTPUnit拥有一个很棒的界面(不需要太多代码),但是最新版本会提交重复请求。

HTMLUnit可以使用,但对于JavaScript的支持似乎有限。不过我已经能够将其用于基本的网页了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接