0

PoolingClientConnectionManager で HttpClient 4.2.1 を使用していますが、使用後に http 接続を取得しようとするとアプリがハングし始めることがわかりました。4.2.1 はコンテンツのストリームを閉じてプールへの接続を返すことに依存しているため、この症状は HttpEntity の消費に失敗した場合によくある間違いのようです。

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;
}

ご覧のとおり、クライアントが 2 つあります。標準クライアントをラップするキャッシュ 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 に答える