82

google-api-client-java 1.2.1-alpha を使用して POST リクエストを実行しています。HttpRequest を execute() すると、次のスタック トレースが取得されます。

以前の POST から同じ URL への 403 エラーをキャッチして無視し、後続の要求にトランスポートを再利用した直後に発生します。(同じ ATOM フィードに複数のエントリを挿入するループ内にあります)。

403 の後で「クリーンアップ」するためにすべきことはありますか?

Exception in thread "main" java.lang.IllegalStateException: Invalid use of SingleClientConnManager: connection still allocated.
Make sure to release the connection before allocating another one.
    at org.apache.http.impl.conn.SingleClientConnManager.getConnection(SingleClientConnManager.java:199)
    at org.apache.http.impl.conn.SingleClientConnManager$1.getConnection(SingleClientConnManager.java:173)
    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:390)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:641)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:576)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:554)
    at com.google.api.client.apache.ApacheHttpRequest.execute(ApacheHttpRequest.java:47)
    at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:207)
    at au.com.machaira.pss.gape.RedirectHandler.execute(RedirectHandler.java:38)
    at au.com.machaira.pss.gape.ss.model.records.TableEntry.executeModification(TableEntry.java:81)

以下のコードが新しい接続を取得しようとするのはなぜですか?

4

9 に答える 9

83

別のリクエストで接続を再利用する前に、レスポンス本文を使用する必要があります。応答ステータスを読み取るだけでなく、応答InputStreamを最後のバイトまで完全に読み取って、読み取りバイトを無視する必要があります。

于 2011-01-07T01:28:43.677 に答える
42

Jetty で HttpClient を使用してテスト フレームワークを構築するときに、同様の問題に直面していました。クライアントからサーブレットへの複数のリクエストを作成する必要がありましたが、実行時に同じ例外が発生していました。

http://foo.jasonhudgins.com/2010/03/http-connections-revisited.htmlで代替案を見つけました

次のメソッドを使用して、クライアントをインスタンス化することもできます。

public static DefaultHttpClient getThreadSafeClient()  {

    DefaultHttpClient client = new DefaultHttpClient();
    ClientConnectionManager mgr = client.getConnectionManager();
    HttpParams params = client.getParams();
    client = new DefaultHttpClient(new ThreadSafeClientConnManager(params, 

            mgr.getSchemeRegistry()), params);
    return client;
}
于 2011-07-18T18:36:22.453 に答える
9

同様の例外メッセージ(少なくともApache Jarkata Commons HTTPクライアント4.2以降)は次のとおりです。

java.lang.IllegalStateException: Invalid use of BasicClientConnManager: connection still allocated. Make sure to release the connection before allocating another one.

この例外は、2つ以上のスレッドが単一のスレッドと相互作用する場合に発生する可能性がありますorg.apache.http.impl.client.DefaultHttpClient

DefaultHttpClient4.2インスタンスをスレッドセーフにするにはどうすればよいですか( 2つ以上のスレッドが上記のエラーメッセージを表示せずにスレッドセーフと対話できるという意味でスレッドセーフ)。!の形式でDefaultHttpClient接続プールを提供します。ClientConnectionManagerorg.apache.http.impl.conn.PoolingClientConnectionManager

/* using
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.2.2</version>
    </dependency>
*/

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.impl.conn.SchemeRegistryFactory;
import org.apache.http.params.HttpParams;
import org.apache.http.client.methods.HttpGet;

public class MyComponent {

    private HttpClient client;

    {
        PoolingClientConnectionManager conMan = new PoolingClientConnectionManager( SchemeRegistryFactory.createDefault() );
        conMan.setMaxTotal(200);
        conMan.setDefaultMaxPerRoute(200);

        client = new DefaultHttpClient(conMan);

        //The following parameter configurations are not
        //neccessary for this example, but they show how
        //to further tweak the HttpClient
        HttpParams params = client.getParams();
        HttpConnectionParams.setConnectionTimeout(params, 20000);
        HttpConnectionParams.setSoTimeout(params, 15000);
    }


    //This method can be called concurrently by several threads
    private InputStream getResource(String uri) {
        try {
            HttpGet method = new HttpGet(uri);
            HttpResponse httpResponse = client.execute(method);
            int statusCode = httpResponse.getStatusLine().getStatusCode();
            InputStream is = null;
            if (HttpStatus.SC_OK == statusCode) {
                logger.debug("200 OK Amazon request");
                is = httpResponse.getEntity().getContent();
            } else {
                logger.debug("Something went wrong, statusCode is {}",
                        statusCode);
                 EntityUtils.consume(httpResponse.getEntity());
            }
            return is;
        } catch (Exception e) {
            logger.error("Something went terribly wrong", e);
            throw new RuntimeException(e);
        }
    }
}
于 2013-02-07T22:50:58.383 に答える
8

これはよくある質問です。BalusC の応答は正しいです。HttpReponseExceptionをキャッチして、HttpResponseException を呼び出してください。応答。() を無視します。エラー メッセージを読む必要がある場合は、response を使用します。parseAsString () 応答のコンテンツ タイプがわからない場合、またはコンテンツ タイプがわかっている場合は応答を使用します。parseAs (MyType.class)。

youtube-jsonc-sample のYouTubeSample.javaからの単純なコード スニペット(ただし、通常、実際のアプリケーションではよりスマートに実行する必要があります)。

  } catch (HttpResponseException e) {
    System.err.println(e.response.parseAsString());
  }

完全開示: 私はgoogle-api-java-clientプロジェクトの所有者です。

于 2011-01-10T14:44:08.427 に答える
3

単体テストの jax-rs (resteasy)Responseオブジェクトで同じ問題が発生しました。これを解決するには、response.releaseConnection(); releaseConnection()-Method を呼び出して resteasy オブジェクトにのみ使用するため、 from からへClientResponseのキャストを追加する必要がありました。ResponseClientResponse

于 2012-10-18T09:00:01.883 に答える
0

次のように InputStream を読み取ります。

if( response.getStatusLine().getStatusCode() == 200 ) {
    HttpEntity entity = response.getEntity();
    InputStream content = entity.getContent();
    try {
        sb = new StringBuilder();
        BufferedReader bufferedReader = new BufferedReader( new InputStreamReader( content ), 8 );
        String line;
        while( ( line = bufferedReader.readLine() ) != null ) {
            sb.append( line );
        }
        bufferedReader.close();
        content.close();
    } catch( Exception ex ) {
        Log.e( "statusCode", ex.getMessage() + "" );
    }
}
于 2014-08-24T14:26:37.500 に答える
0

OK、同様の問題があります。これらのソリューションはすべて機能しません。いくつかのデバイスでテストしました。問題はデバイスの日付でした。2013 年ではなく 2011 年でした。これも役立つかどうかを確認してください。

于 2013-02-08T11:42:17.380 に答える