0

我正在将 HttpClient 4.2.1 与 PoolingClientConnectionManager 一起使用,并且我发现我的应用程序将在尝试获取 http 连接后开始挂起。如果您未能使用 HttpEntity,则此症状似乎是一个常见错误,因为 4.2.1 依赖于关闭 Content 的流以将其返回到池的连接。

这是我组装 HttpClients 及其池的方式

HttpClient standardClient = null;
HttpClient cachedClient = null;
PoolingClientConnectionManager connectionManager = null;

protected synchronized HttpClient getStandardClient() {
  if ( standardClient == null ) {
    connectionManager = new PoolingClientConnectionManager();
    connectionManager.setMaxTotal(2);
    connectionManager.closeIdleConnections(120, TimeUnit.SECONDS);
    standardClient = new DecompressingHttpClient( new DefaultHttpClient (connectionManager));
    Log.i(tag, "Creating ConnectionManager and standard http client");
  }

  return standardClient;
}

protected synchronized HttpClient getCachedClient() {
  if ( cachedClient == null ) {
    CacheConfig cacheConfig = new CacheConfig();
    cacheConfig.setMaxObjectSize( 512*1024 );
    cacheConfig.setMaxCacheEntries( 10 );

    cachedClient = new CachingHttpClient(getStandardClient(),
                                         getCacheStorage(),
                                         cacheConfig);
    Log.i(tag, "Creating CachingHttpClient");
  }

  return cachedClient;
}

如您所见,我有两个客户。包装标准客户端的缓存 http 客户端。

现在我发现,如果我删除 cachedClient 并且只使用 standardClient,我不会遇到池挂起和孤立连接的任何问题。

查看 CachingHttpClient 的源代码,它似乎没有使用底层实体。有没有其他人经历过这个?

任何人都可以看到我的代码中的任何错误以及我是如何配置和使用 HttpClient 的吗?有谁知道我可以在我的代码中做些什么来正确地让后端实体被正确使用?

顺便说一句,这是我使用 http 客户端并使用它们的方式......

HttpClient httpClient = cacheOkay ? getCachedClient() : getStandardClient();  
HttpResponse response = httpClient.execute(request, localContext);
HttpEntity resEntity = response.getEntity();  

int responseStatus = response.getStatusLine().getStatusCode();

byte[] responseBody = EntityUtils.toByteArray(resEntity);
EntityUtils.consume(resEntity);

此外,对于那些想知道这是在 Android 上的人,我使用 JarJar 将 HttpClient 4.2.1 重新打包为备用包结构,因此它不会与 Android 附带的旧 HttpClient 类冲突。但尽管重新打包代码是 100% 4.2.1。我只是提到这一点是为了避免在 Android 上运行 HttpClient 4.2.1 时出现任何冲突建议。

4

1 回答 1

0

因此,在解决了这个问题后,我非常确信这是 HttpCommons 中的一个错误。该错误似乎是 HttpCachingClient 没有正确使用来自后端 HttpClient 的 HttpEntity。在我们的例子中,由于这是一个池化客户端,因此可以防止连接每次返回池。

我的工作是确保 HttpCachingClient 关闭来自后端客户端的流。

这是用于创建缓存客户端的修改代码

    protected synchronized HttpClient getCachedClient() {
      if ( cachedClient == null ) {
        CacheConfig cacheConfig = new CacheConfig();
        cacheConfig.setMaxObjectSize( 512*1024 );
        cacheConfig.setMaxCacheEntries( 10 );
        cachedClient = new CachingHttpClient(getStandardClient(),
                                             new HeapResourceFactory() {
                                               @Override
                                               public Resource generate(String requestId,InputStream instream,InputLimit limit) throws IOException {
                                                    try {
                                                      return super.generate(requestId, instream, limit);
                                                    }
                                                    finally {
                                                      instream.close();
                                                    }
                                                }
                                             },
                                             application.getCacheStorage(),
                                             application.getCacheConfig());
        Log.i(tag, "Creating CachingHttpClient");
    }

    return cachedClient;
}

所以基本上我将 HeapResourceFactory 子类化并添加了 instream.close() 以确保它使用该后端实体。

于 2012-11-20T19:14:47.590 回答